Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在应用程序代码(如@Transactional)中设置隔离级别与在db服务器上配置的隔离级别之间有什么关系?_Java_Mysql_Spring Jdbc_Spring Transactions_Transaction Isolation - Fatal编程技术网

Java 在应用程序代码(如@Transactional)中设置隔离级别与在db服务器上配置的隔离级别之间有什么关系?

Java 在应用程序代码(如@Transactional)中设置隔离级别与在db服务器上配置的隔离级别之间有什么关系?,java,mysql,spring-jdbc,spring-transactions,transaction-isolation,Java,Mysql,Spring Jdbc,Spring Transactions,Transaction Isolation,我很难把所有的信息拼凑在一起。让我尽可能详细地解释一下 在SpringJDBC、SpringTransaction和MySQLDB应用程序上工作时,我希望能够在选择更新时锁定表中的数据行。原因是,我有在不同阶段转换数据的业务逻辑。所以,如果应用程序实例(在服务器1上)拾取记录进行处理,那么它不应该被另一个实例拾取。这有点类似于。但我不能接受这个答案,原因与OP对这个问题的回答相同 因此,在仔细检查并了解如何使用jdbcTemplate配置事务管理之后,我的spring应用程序设置如下(仅相关部分

我很难把所有的信息拼凑在一起。让我尽可能详细地解释一下

在SpringJDBC、SpringTransaction和MySQLDB应用程序上工作时,我希望能够在选择更新时锁定表中的数据行。原因是,我有在不同阶段转换数据的业务逻辑。所以,如果应用程序实例(在服务器1上)拾取记录进行处理,那么它不应该被另一个实例拾取。这有点类似于。但我不能接受这个答案,原因与OP对这个问题的回答相同

因此,在仔细检查并了解如何使用jdbcTemplate配置事务管理之后,我的spring应用程序设置如下(仅相关部分):

applicationContext.xml

...
...
<context:annotation-config />
...
<context:component-scan base-package="org.foo.bar"/>
...
<!-- Enable Annotation based Declarative Transaction Management -->
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" />
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
...
<bean id="dataSource"
      class="org.apache.commons.dbcp2.BasicDataSource"  destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://dbserver:3306" />
    <property name="username" value="foo" />
    <property name="password" value="baz" />
    <property name="initialSize" value="10" />
    <property name="maxTotal" value="20"/>
</bean>
如果不更改这些设置,我无法获取
SELECT。。。使更新
生效

一旦我手动测试了它,我想看看这在我的应用程序代码运行时是否有任何影响。因此,当我保持一个mysql命令行会话处于活动状态时,我启动了我的应用程序,并在
dbAccessService.updateRecord()处设置了一个断点行。然后在另一个会话中,我尝试选择这一行(没有
selectforupdate
,只是一个简单的
select
)语句。现在我可以看到,由于应用程序代码启动的上一个事务,该行被锁定

问题:

  • 要通过spring事务实现行锁定(
    SELECT…FOR UPDATE
    behavior),我必须更改数据库服务器上的设置吗?比如隔离级别和自动提交
  • 假设MySQL服务器在默认情况下运行(隔离级别=可重复读取,自动提交=1)。现在这还能用吗?也就是说,若我像上面所做的那个样在spring的目标方法中配置事务,那个么应用程序的一个实例正在读取的一行是否会保持锁定状态,以便尝试读取该行的任何其他实例都会被阻止
  • 我们在
    @Transactional
    注释上添加的配置如何影响数据库?我知道我们可以为不同的作用域设置事务特征,如的表13.9所述。下面是我对这一切如何运作的想象或猜测。对吗
  • 这一切是如何运作的

    • 用@Transactional注释的类/方法将创建一个代理对象,以便添加所有事务性内容以及用户实现的业务逻辑
    • 获取数据库连接并创建数据库会话
    • 对于此会话,根据
      @Transactional
      中提供的配置,设置了适当的隔离级别(不知道自动提交会受到怎样的影响)
    • 事务完成后,会话关闭。创建的任何新会话都将相应地设置隔离特性

    • 有没有更好的方法让我达到想要的
      SELECT。。。对于spring jdbc、spring tx的更新
      功能?我可能会引入我自己的锁定机制,比如引入一个新的布尔列,比如
      selected\u for\u processing
      ,而不是选择,通过设置
      selected\u for\u processing
      列来更新要选择的记录。在下一步中,我将根据此标志和另一个状态标准进行选择。因此,这样一条记录只会被处理一次。但我想知道是否有一种传统的或配置的方式来实现这一点?我不能使用JPA或任何spring-data-x库。spring数据库使用springframework 5.x.x或更高版本,但我一直使用springframework 4.2.3,因此使用SpringJDBC和spring-tx

    产生影响的是自动提交。正常自动提交处于启用状态(每个查询本身就是一个事务),要使用事务,您需要在代码中使用
    BEGIN
    START transaction
    ,执行事务中需要执行的操作,然后显式调用
    commit

    1) 服务器上的事务隔离设置将更改服务器上的默认设置。但您可以在开始事务之前在本地会话中更改它们,而无需更改服务器范围的默认值

    2) 是的,不同会话之间的tx_隔离可能不同


    3) 我不确定我是否能完全回答这个问题,因为它似乎是针对Spring的,我在这方面不太流利。但是,一般来说,Spring在没有显式锁定整个表的情况下,无法确保或实现数据库级别的事务性和锁定,因此它最终只能使用底层数据库功能,试图比底层数据库更聪明,必然会带来巨大的性能和并发性损失。

    必须关闭自动提交才能锁定工作

    如果启用,则每个SQL语句都是它自己的事务。因此,SELECT语句将获取锁,但在执行SELECT之后,在运行update语句之前,它将立即释放锁。如果您的dbAccessService bean是hibernate DAO,那么它发出的SQL语句可能是一个all columns更新,类似于放入REST(而不是补丁)的行为。这可能导致现有的更新被完全替换

    Tx A Tx B 选择id=1的位置进行更新 尝试相同操作,但锁定与tx A一起,因此在等待锁定时被阻止 释放锁(因为自动提交) 获取id=1的select的锁 尝试更新但被阻止(更新隐式获得锁) 释放锁 更新foo SET col_a=val_a,col_b=val_b,status='PROCESSING' 等待锁 更新完成,释放锁 更新foo SET col_a=val_a,col_b=val_b,status='PROCESSING'
    谢谢你的回答。关闭“自动提交”听起来有点不切实际否?我的意思是想象一下如果ev
    public class TransactionSvcImpl implements TransactionSvc {
        @Autowired
        DatabaseAccessService dbAccessService;
    
        @Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRES_NEW)
        @Override
        public List<Foo> getFooForUpdate() {
            // Below call executes a SQL like - "SELECT * FROM some_t WHERE id = 1 FOR UPDATE"
            List<foo> foos = dbAccessService.getSomeRecord();
            dbAccessService.updateTheRecord(foos, Status.PROCESSING);
            return foos;
        }
    }
    
    SET tx_isolation = 'SERIALIZABLE';
    SET AUTOCOMMIT=0;