TransactionDefinitio 7 种传播行为
int PROPAGATION_REQUIRED = 0; | 支持当前事务,如果没有则开启新的事务 |
int PROPAGATION_SUPPORTS=1 | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
int PROPAGATION_MANDATORY = 2 | 支持当前事务, 如果没有事务则会抛出异常。 throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'") |
int PROPAGATION_REQUIRES_NEW = 3; | 创建一个新的事务, 事务相互独立,如果当前存在事务,则中断;它拥有自己的隔离范围, 自己的锁。 |
int PROPAGATION_NOT_SUPPORTED = 4; | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 |
int PROPAGATION_NEVER = 5 | 不支持当前事务,如果存在则直接抛出异常 |
int PROPAGATION_NESTED = 6 | 嵌套事务。它是已经存在事务的⼀个真正的⼦事务. 潜套事务开始执⾏时, 它将取得⼀个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的⼀部分, 只有外部事务结束后它才会被提交. (并不是鸡肋的存在) |
事务失效的原因
1 必须时public 修饰
2 在同一个类的方法调用。 事务失效, ( 因为走的不是代理对象, 而是代理对象,所以没走DynamicAdvisedInterceptor的逻辑。解决方法: 可以自己依赖自己 )
3 @Transactional 注解参数rollbackFor 的回滚类, 源码见下面分析
4 数据库引擎不支持事务
5 不正确捕获异常 try catch
以下:传播行为的异常
6 使用了传播行为:PROPAGATION_NOT_SUPPORTED
传播行为的报错
1 PROPAGATION_MANDATORY
支持当前事务, 如果没有事务则会抛出异常。
throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'")
2 PROPAGATION_REQUIRED
throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");
因为在事务链中, 有多个方法使用了PROPAGATION_REQUIRED 的传播行为, 其中一个方法抛出异常,并将连接设置为 已回滚getConnectionHolder().setRollbackOnly();, 然后使用了方法使用了 try catch 捕获。 提交事务时, 发现已回滚则抛出异常。 (这种情况的解决:可以参考一下嵌套事务的 PROPAGATION_NESTED, 当然具体问题具体分析)
TransactionInterceptor在方法体
1.创建事务信息
invokeWithinTransaction 中createTransactionIfNecessary 创建事务信息,TransactionInfo
doGetTransaction() 获取对象DataSourceTransactionObject。类图如下
到这里返回 DefaultTransactionStatus 实例
方法 doBegin() 则获取数据库来连接, 并绑定当前线程。
最终 prepareTransactionInfo() 创建事务信息 new TransactionInfo();并将事务信息绑定线程。
txInfo.bindToThread(); 如果当前有
TransactionAspectSupport中
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<>("Current aspect-driven transaction");
transactionInfoHolder获取事务则直接赋值给当前对象的oldTransactionInfo;新事务信息
会形成一个单向的节点链
2 回滚,抛出异常,并释放资源
对异常回滚的判断,是否需要回滚
对回滚异常的判断, 判断类RuleBasedTransactionAttribute
回滚异常类的判断
最后采用递归的方式, 对异常的名字进行判断;这也是很有可能事务失效的原因之一。
a.@Transactional(rollbackFor = NullPointerException.class) 获取注解参数rollbackFor 的名字进行判断,exceptionClass.getName().contains(this.exceptionName),且递归深度要小于Integer.MAX_VALUE
b 在满足a条件的基础之上,当winner!=null,且要不属于NoRollbackRuleAttribute 类型,才会事务回滚
c 如果@Transactional 注解参数rollbackFor 为空,则判断为ex instanceof RuntimeException || ex instanceof Error, 否则事务也会失效
释放来连接资源, 并关闭资源
3 final
5 finally 将 transactionInfoHolder
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<>("Current aspect-driven transaction")
不管成功还是失败,将transactionInfoHolder的值设置为上一个事务对象oldTransactionInfo