spring逻辑事务和物理事务区别

2021-11-28 10:48:53 浏览数 (1)

理解本篇文章需要的知识储备:

  1. JDBC,connection事务提交方式
  2. mybatis sqlsession的开启和关闭,相当于connection的一次开启和关闭

我们把事务传播过程中的外层称为调用者,内层称为被调用者

物理事务:一次connection(相当于mybatis的一次sqlsession)的开启和关闭,其间的所有数据库操作

逻辑事务:被@Transactional注解修饰的操作,具体根据传播行为来判断是否是逻辑事务

被调用者中(调用者已经存在事务),只有PROPAGATION_REQUIRES_NEW传播行为开启了一个新的物理事务,其他传播行为都是逻辑事务

下面通过代码分析

github代码地址,欢迎大家一起参与开源

Propagation.REQUIRED事务传播方式

调用者代码:

代码语言:txt复制
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)

  public void requestTransactional() {

    userService.addUser(6, "user6");



    userServiceTransactionStateInvoked.requestTransactional();

  }

被调用者代码:

代码语言:txt复制
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)

  public void requestTransactional() {

    userService.addUser(6, "user6");

  }

调用者和被调用者的事务传播行为都是:Propagation.REQUIRED

执行代码日志如下:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

我们一步步分析两次插入数据代码执行流程:

  1. 创建SqlSession
  2. 注册事务到sqlsession
  3. 事务持有一个connection
  4. 开始执行第一次插入操作,并成功
  5. 释放当前sqlsession
  6. 发现第二次插入和第一次插入同属于要一个物理事务
  7. 第二次插入获取sqlsession
  8. 执行sql
  9. 释放sqlsession
  10. 发现事务中有方法执行失败
  11. JDBC标记事务需要回滚
  12. 事务取消注册
  13. sqlsession执行close操作
  14. JDBC回滚init
  15. connection执行回滚操作,执行完毕释放connection

执行过程中两次插入数据属于两个不同的逻辑事务,但是他们同属于一个物理事务(因为sqlsession和connection)始终是同一个。

一步步分析下来对逻辑事务和物理事务将会有一个直观的认识。

Propagation.REQUIRES_NEW事务传播方式

调用者代码:

代码语言:txt复制
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)

  public void requiresNewTransactional() {

    userService.addUser(6, "user6");



    userServiceTransactionStateInvoked.requiresNewTransactional();



    userService.addUser(6, "user6");

  }

被调用者代码:

代码语言:txt复制
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)

  public void requiresNewTransactional() {

    userService.addUser(7, "user7");

  }

执行代码日志如下:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

分析3次插入数据代码执行流程的关键步骤:

  1. 创建sqlsession
  2. 注册事务
  3. 使用spring容器管理JDBC connection
  4. 第一次数据插入成功后释放sqlSession
  5. 暂停当前事务创建新的事务(***注意:这就是在创建新的物理事务***)
  6. 创建新的sqlsession
  7. 注册新事务
  8. 注册新的connection连接
  9. 第二次数据插入成功
  10. 关闭sqlsession,执行commit,释放connection
  11. 恢复第一次创建的事务,并执行第三次数据插入
  12. 关闭sqlsession(注意观察sqlsession唯一标识)
  13. 第三次数据插入失败,进行事务回滚,第一次数据虽然插入成功,但是和第二次数据插入同处同一个物理事务,所以也被回滚。
  14. 释放第一次的connection(注意观察connection唯一标识)

最终执行结果:第一次和第三次数据插入失败,只有第二次插入数据成功。

0 人点赞