一、springboot的事务事务管理
我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合。由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,之前成功操作数据的并不可靠,需要在这种情况下进行回退。
事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态。
事务管理是Spring框架中最为常用的功能之一,我们在使用Spring Boot开发应用时,大部分情况下也都需要使用事务。
二、springboot事务管理方式
spring支持编程式事务管理和声明式事务管理两种方式。
编程式事务管理
编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务管理
声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。
**@Transactional **注解的方式,是目前流行的使用方式,下面简单介绍一下,如何使用@Transactional注解方式的事务
三、使用@Transactional 注解进行事务管理
1.启用事务管理功能
在关键类中添加 注解 @EnableTransactionManagement,开启事务支持
如,app入口类
@SpringBootApplication(scanBasePackages = {"com.a.b.c", "cn.afterturn.easypoi"})
@EnableCaching
@EnableFeignClients
@EnableScheduling
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class MyApplication { public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
或者 mybatis配置类中
@EnableTransactionManagement
@Configuration
@MapperScan(basePackages = {"com.a.b.c.*"})
public class MybatisPlusConfig {}
2.添加@Transactional到对应的方法中
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Transactional
public void transfer(int outter, int inner, Integer money) {
accountDao.moveOut(outter, money); //转出
int i = 1/0; // 抛出异常
accountDao.moveIn(inner, money); //转入
}
}
在方法transfer上添加了@Transactional的注解,运行后,抛出异常,事务生效。
3.@Transactional对异常的拦截
上文的事务写法,一切都非常顺利,但是,如果transfer方法体内抛出异常的方式,修改为Exception,如下
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Transactional
public void transfer(int outter, int inner, Integer money) {
accountDao.moveOut(outter, money); //转出
throw new Exception("失败!"); // 抛出异常
accountDao.moveIn(inner, money); //转入
}
}
那么,事务就不奏效了,为什么呢?
因为,@Transactional 注解的方式,是基于Spring AOP的事务管理 ,即声明式事务管理,默认是针对RuntimeException回滚,即默认只对RuntimeException()及其子类进行事务回滚;非运行时类型的异常默认是不会回滚的。

spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获 RuntimeException 的异常,但可以通过配置来捕获特定的异常并回滚
换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
所以, 默认情况下,非运行时类型的异常默认是不会回滚的。
故,要实现任何异常情况的回滚,则需要修改@Transactional的属性rollbackFor的值为Exception.class
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDao accountDao;
@Transactional(rollbackFor=Exception.class)
public void transfer(int outter, int inner, Integer money) {
accountDao.moveOut(outter, money); //转出
throw new Exception("失败!"); // 抛出异常
accountDao.moveIn(inner, money); //转入
}
}
网友评论