引言
在业务开发操作数据库过程中,我们基本都会涉及事务的操作,事务可以保证业务逻辑的完整性。所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务、提交事务来完成数据操作,或者在发生错误的时候回滚数据。而Spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理。Spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现。
编程式事务
编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
数据访问技术 | 封装类 |
JDBC | DataSourceTransactionManager |
JPA | JpaTransactionManager |
Hibernate | HibernateTransactionManager |
JDO | JdoTransactionManager |
分布式事务 | JtaTransactionManager |
@Resource
TransactionTemplate transactionTemplate;
// 使用TransactionTemplate编程事务
@Override
public void sendMessage(Integer usId, String content) {
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(new TransactionCallback() {
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
try {
Message message = new Message();
for (int i = 0; i < 5; i++) {
if(i == 3){
throw new RuntimeException();
}
message.setContent(content);
message.setUsId(usId);
messageMapper.insert(message);
}
} catch (Exception e) {
transactionStatus.setRollbackOnly();
e.printStackTrace();
}
return null;
}
});
}
@Resource
private DataSourceTransactionManager transactionManager;
// 使用transactionTemplate编程事务
@Override
public void sendMessage(Integer usId, String content) {
//定义事务隔离级别,传播行为,
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;
//获取事务状态后,Spring根据传播行为来决定如何开启事务
TransactionStatus status = transactionManager.getTransaction(def);
List<User> list = userMapper.selectAll();
int i = list.size();
System.out.println("表中记录总数:"+i);
try {
User user = new User();
user.setName("test_test");
userMapper.addUser(user);
transactionManager.commit(status); //提交status中绑定的事务
} catch (RuntimeException e) {
transactionManager.rollback(status); //回滚
}
i = userMapper.selectAll().size();
System.out.println("表中记录总数:"+i);
}
声明式事务
编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现。
声明式事务管理使用了 AOP 实现的,本质就是在目标方法执行前后进行拦截。在目标方法执行前加入或创建一个事务,在执行方法执行后,根据实际情况选择提交或是回滚事务。
@Transactional 注解配置事务管理
常用参数说明
参 数 名 称 | 功 能 描 述 |
readOnly | 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true) |
rollbackFor | 该属性用于设置需要进行回滚的异常类数组。@Transactional(rollbackFor={RuntimeException.class, Exception.class}) |
rollbackForClassName | 该属性用于设置需要进行回滚的异常类名称数组。@Transactional(rollbackForClassName={“RuntimeException”,”Exception”}) |
noRollbackFor | 该属性用于设置不需要进行回滚的异常类数组。@Transactional(noRollbackFor={RuntimeException.class, Exception.class}) |
noRollbackForClassName | 该属性用于设置不需要进行回滚的异常类名称数组。@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”}) |
propagation | 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) |
isolation | 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可 |
timeout | 该属性用于设置事务的超时秒数,默认值为-1表示永不超时 |
事务传播行为
事务传播行为用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时事务如何传播。
- REQUIRED :如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- REQUIRES_NEW :创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- NOT_SUPPORTED :以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- NEVER :以非事务方式运行,如果当前存在事务,则抛出异常。
- NESTED :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED
@Transactional注解实现原理
使用@Transactional注解对某目标方法进行标注时,Spring会使用AOP代理,生成一个代理对象,该对象会根据@Transactional注解的属性配置信息,来决定是否使用TransactionInterceptor拦截器来进行拦截。如果该方法需要使用事务控制,则需要使用TransactionInterceptor事务拦截器,对该方法进行拦截,在该目标方法执行之前创建并开启事务,然后执行目标方法,最后在目标方法执行完毕后,根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager操作数据源DataSource提交或回滚事务。
注意事项
- @Transactional只作用于public方法
- 在同一个类中的一个 @Transactional 方法中,去掉用另一个 @Transactional 方法,会导致第二个方法的事务无效(但是事务可以传递,可以看看上面的内容)。
- 对方法进行try-catch后 捕捉异常,则事物就失效了。需要手动回滚事务
// 异常捕获事务无效,需手动执行回滚
@Transactional(rollbackFor = Exception.class)
public void test1() {
try{
// 业务逻辑
}catch(Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
e.printStackTrace();
}
}
- 还可根据回滚点回滚事务
//设置回滚点
Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
// 业务逻辑
//回滚到savePoint
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
事务失效的原因
- 非public方法修饰符:由于Spring的事务是基于AOP的方式结合动态代理来实现的。因此事务方法一定要是public的,这样才能便于被Spring做事务的代理和增强。
- 非事务方法调用事务方法/事务方法调用了非事务方法
- 事务方法的异常被捕获了:异常被捕获处理了,没有抛出异常
- 事务异常类型不对:设置了rollbackFor,但事务方法抛出了其他异常类型
- 事务传播行为不对
- 类没有被Spring类管理
总结
本篇文章主要介绍了spring boot对事务的一些操作,希望对大家有用~~