事务

  • 事务常用类
  • TransactionSynchronizationManager
  • afterCommit
  • 事务配置
  • Aop配置
  • 切点的配置
  • @Transaction配置
  • 事务传播属性
  • PROPAGATION_REQUIRED
  • PROPAGATION_SUPPORTS
  • PROPAGATION_MANDATORY
  • PROPAGATION_REQUIRES_NEW
  • PROPAGATION_NOT_SUPPORTED
  • PROPAGATION_NEVER
  • PROPAGATION_NESTED
  • 场景说明
  • 事务传播属性与connection关系
  • propagation="NEVER”
  • 无事务配制无传播属性
  • 事务隔离级别
  • 隔离级别种类
  • ISOLATION_DEFAULT
  • ISOLATION_READ_UNCOMMITTED
  • ISOLATION_READ_COMMITTED
  • ISOLATION_REPEATABLE_READ
  • ISOLATION_SERIALIZABLE
  • 隔离级别的场景
  • 隔离级别的原理


事务常用类

TransactionSynchronizationManager

afterCommit

spring service不提交事务 查询新增结果_数据

事务配置

Aop配置

<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
 
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
    <!-- 以方法为单位,指定方法应用什么事务属性 isolation:隔离级别 propagation:传播行为-->
    <tx:method name="doTx*" isolation="READ_COMMITED" propagation="REQUIRED" />
    <tx:method name="doInvoke*" isolation="READ_COMMITED" propagation="REQUIRED" />
    <tx:method name="doNewTx*" isolation="READ_COMMITED" propagation="REQUIRES_NEW" />
    <tx:method name="doNoTx*" isolation="READ_COMMITED" propagation="NOT_SUPPORTED" />
    </tx:attributes>
</tx:advice>

<!-- 配置织入 -->
<aop:config>
    <!-- 配置切点表达式 -->
    <aop:pointcut expression="execution(* com.mskj.service.*ServiceImpl.*(..))" id="txPointcut" />
    <!-- 配置切面 : 通知+切点 advice-ref:通知的名称 pointcut-ref:切点的名称 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref=" txPointcut " />
</aop:config>

切点的配置

(1)第一个*表示方法的返回值是任意的
(2) service.*ServiceImpl表示service包下以ServiceImpl结尾的class
(3) service.*ServiceImpl.*表示service包下以ServiceImpl结尾的class的所有方法
(4)(…)表示方法参数任意

@Transaction配置

如果要使用@Transaction注解则必须配置

<tx:annotation-driven transaction-manager="transactionManager" mode="proxy" proxy-target-class="false"/>

事务传播属性

PROPAGATION_REQUIRED

如果存在一个事务,则支持当前事务。如果没有事务则开启新的事务。

PROPAGATION_SUPPORTS

如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。

PROPAGATION_MANDATORY

如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

PROPAGATION_REQUIRES_NEW

总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

PROPAGATION_NOT_SUPPORTED

总是非事务地执行,并挂起任何存在的事务

PROPAGATION_NEVER

总是非事务地执行,如果存在一个活动事务,则抛出异常

PROPAGATION_NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

场景说明

spring service不提交事务 查询新增结果_java_02


交易正向处理流程:(业务库中的处理无跨库事务)

1 事务开启(REQUIRED)

2 记录技术流水,使用独立事务(REQUIRES_NEW) 这步要是出现异常 后续操作不会执行

3 在业务库读取业务数据(REQUIRED)(会在第5步结束之后事物挂起 最后提交见下方说明)

4 在业务库新增业务数据(REQUIRED)

5 在业务库修改业务数据(REQUIRED)

6 读取公共库的数据,不使用事务(NOT_SUPPORTED)

7 修改技术流水状态,使用独立事务(REQUIRES_NEW)

以下场景均经过测试验证:

1) 均无异常

第2步获取数据库连接1,并直接提交事务;

第3步获取新的数据库连接2,并在第5步之后挂起;

第6步获取新的数据库连接3,并读取数据成功;

第7步获取新的数据库连接4,并独立提交事务;

第3步获取的数据库连接2所对应的事务,最后提交。

2) 第2步记录技术流水异常,独立事务回滚,后续操作均不执行。

注意:模拟测试与实际场景不同,实际情况下,技术流水的记录由拦截栈来处理,流水记录失败是否进行后续业务操作,请以平台代码为准。

3) 第5步修改业务数据异常,第2步的流水记录新增正常提交,第4步的insert操作回滚,后续操作不执行。

4) 第6步读取公共库数据异常,第2步的流水记录新增正常提交,第4步的insert操作、第5步的update操作回滚,后续操作不执行。

注意:最外层的事务回滚,是因为第6步的异常抛到了外层,如果第6步内部处理掉异常,则不会导致最外层事务回滚。

事务传播属性与connection关系

propagation="NEVER”

当传播属性为never时 执行操作时,connection还是与线程变量绑定,一直都是同一个connection在操作 测试结果如下:

spring service不提交事务 查询新增结果_数据_03


spring service不提交事务 查询新增结果_隔离级别_04


edit connection hashcode=181260145

updateById connection hashcode=181260145

无事务配制无传播属性

每一次的更新 都分别从DataSourceUtils里面重新获取一个新连接 就没有把连接绑定到线程变量这一说了

spring service不提交事务 查询新增结果_后端_05


spring service不提交事务 查询新增结果_spring_06

事务隔离级别

spring提供了5种隔离级别

隔离级别种类

ISOLATION_DEFAULT

这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别

ISOLATION_READ_UNCOMMITTED

这是事务最低的隔离级别,它允许令外一个事务可以看到这个事务未提交的数据 会出现脏读 用的较少

ISOLATION_READ_COMMITTED

比较常用 :保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据

spring service不提交事务 查询新增结果_隔离级别_07

ISOLATION_REPEATABLE_READ

这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。事务在执行期间看到的值必须是一直的 会出现幻读

先看下方的隔离级别场景图,然后看完了后再看这张图

spring service不提交事务 查询新增结果_隔离级别_08


可重复读下,虽然事务A先启事务,但当他在事务B提交后第一次来查询name值后为修改后的lisi的值, 而不是认为事务A先启动先生成快照又是可重复读以为是zhangsan呢,但测试后为lisi 这个要注意

ISOLATION_SERIALIZABLE

这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 除了防止脏读,不可重复读外,还避免了幻像读 用的很少 严重影响性能

隔离级别的场景

spring service不提交事务 查询新增结果_数据_09

  1. 读未提交一个事务还没提交时,它做的变更就能其它事物看到
  2. 读提交一个事务提交之后,它做的变更才会被其他事务看到
  3. 可重复读一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的 不可见 也可以这样理解 每个事务启动的时候打一个快照,别人改的“我不听我不听” 不可避免出现幻读(比如 拿这个主键查的时候没有记录,当插入时发现有记录了—另一个事物插入的,见鬼了出现幻觉了吗 叫幻读)
  4. 串行化:加锁事物串行化

隔离级别的原理

事务隔离的实现:
每条记录在更新的时候都会同时记录一条回滚操作。
同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。

回滚日志的删除 系统会判断当没有事务需要用到这些回滚日志的时候,回滚日志才会删除