Spring Transaction
Spring Transaction
什么是事务?
事务是一组关联的数据库操作,要么全部成功执行,要么全部回滚,保障了数据库操作的一致性、完整性。Spring本身没有事务,是通过集成和调用持久层实现的事务。
事务的分类
编程式事务
优点:粒度更小,可以在try-catch代码块锁定精确的范围
缺点:配置繁琐、代码耦合度高
1
2
3
4
5
6
7<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
try {
// 在此处执行事务操作
// 例如,插入、更新、删除等数据库操作
// 如果发生异常,事务会被回滚
// 如果一切正常,事务会被提交
} catch (Exception e) {
// 捕捉异常,标记事务为回滚状态
status.setRollbackOnly();
e.printStackTrace();
}
return null;
}
});
声明式事务
- 优点:降低耦合、减少对代码的侵入性、配置简单
- 缺点:@Transactional是方法级的、粒度更大
需要在配置类/文件中配置好
DataSourceTansactionManager
然后添加@EnableTransactionManagement
,就可以开始使用@Transactonal
注解了。
问题:怎么缩小声明式事务的粒度?
将使用事务的方法拆分成小的方法,在整个方法里面调用小方法,在小方法上添加@Transactional
。
事务的实现原理
Spring事务是基于AOP实现的,
对一个方法开启事务对应着用AOP将这个方法增强,使用一个around advice 首先在前置通知事务管理器在方法调用前开启事务,然后执行方法,然后在返回后通知提交事务,或者在抛出后通知回滚事务,然后再在后置通知关闭事务,rollbackfor对应着AOP的catch代码块捕获的异常。这样理解对吗?
@Transactional注解
@Transactional
是spring声明式事务的核心注解;它可以被添加到方法上,起到事务的作用(事务的声明是方法级的);
添加到的方法如果有
unchecked
的(没有被catch的)RuntimeException
及其子类异常,将会触发事务回滚。(编译期异常不会触发)如果方法里面检查了异常比如添加了try-catch代码块,将不会触发事务回滚,如果让事务能够正常回滚,则需要在catch内添加
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
;@Transaction的属性
isolation
指定当前事务的隔离级别,默认是数据库的默认隔离级别**
propagation
**指定传播行为timeOut
指定事务的超时时间,单位是秒,默认值-1(没有超时时间)**
readOnly
**默认是false,声明事务里面有读有写,改成true时,告诉数据库事务中只有读,可以做优化,提高查询效率rollbackFor
指定哪些异常触发回滚rollbackForClass
noRollbackFor
noRollbackForClass
事务的传播行为
事务的传播行为指的是在一个声明了事务的方法中,调用了另外一个声明了事务的方法(嵌套事务),这个时候需要设置事务的传播行为,定义在方法调用链中嵌套事务如何相互影响。
事务的传播行为由propagation属性声明
事务传播行为的分类
REQUIRED 方法调用时,如果调用者已经存在事务,就加入到调用者的事务,如果不存在事务,就开启一个新的事务(使用被调用者的事务)
REQUIRES_NEW 方法调用时,将调用者的事务挂起,开启一个新的事务(使用被调用者的事务),等待新事务返回后继续原来的事务。
NESTED
开启嵌套的两个事务,调用者的事务回滚会影响被调用者,被调用者的回滚不会影响调用者的事务。
NEVER
不允许有别的事务,否则抛异常
思考:propagation属性声明在哪个位置?调用者声明还是被调用者?
被调用者,被调用者根据传播行为来选择自己使用事务的方式。
事务为什么会失效
- 没有正确配置事务、没有开启事务、没有@Transactional注解
- 加了@Transactional但是方法调用中使用了this,绕开了代理。?
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!