声明式事务:基于Spring AOP,通过注解或XML配置实现,有助于用户将操作与事务规则进行解耦。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
本文主要对基于注解的方式叙述。
事务注解:@Transactional,加此注解看作一个事务,要么都成功要么都失败。
纯注解模式下实现事务只需要把注解驱动的注解形式@EnableTransactionManagement 加在Spring的配置类上就可以了。
@Transactional注解用于两种场景:
-
标于类上:表示当前类以及其下无限级子类中所有pubilc方法将被spring自动加上事务。
一般不推荐使用,事务控制的粒度太大。 -
标于方法上:仅对该方法。
当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。 -
标于接口上:表示接口的实现类中所有public方法都被spring自动加上事务
不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效。
@Transactional 只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。
Spring事务失效场景
最常见的:既添加了@Transactional 注解,方法里却又添加了catch语句对业务进行异常捕获,都把异常“吃”掉了,Spring自然不知道这里有错,更不会主动去回滚数据。
参数
参数 | 描述 |
value | 指定事务管理器的bean名称,如果容器中有多事务管理器PlatformTransactionManager,那么得告诉spring,当前配置需要使用哪个事务管理器 |
transactionManager | 同value,value和transactionManager选配一个就行,也可以为空,如果为空,默认会从容器中按照类型查找一个事务管理器bean |
propagation | 事务的传播属性 |
isolation | 事务的隔离级别,就是制定数据库的隔离级别,数据库隔离级别大家知道么?不知道的可以去补一下 |
timeout | 事务执行的超时时间(秒)。执行一个方法,有问题,可能最多只能等5秒, 5秒后,还没有执行完毕,就弹出一个超时异常。 |
readOnly | 是否是只读事务,比如某个方法中只有查询操作,可以指定事务是只读的,设置了这个参数,数据库可能会做一些性能优化,提升查询速度 |
rollbackFor | 定义零(0)个或更多异常类,这些异常类必须是Throwable的子类,当方法抛出这些异常及其子类异常的时候,spring会让事务回滚,如果不配做,那么默认会在 RuntimeException 或者 Error 情况下,事务才会回滚 |
rollbackForClassName | 同 rollbackFor,只是这个地方使用的是类名 |
noRollbackFor | 定义零(0)个或更多异常类,这些异常类必须是Throwable的子类,当方法抛出这些异常的时候,事务不会回滚 |
noRollbackForClassName | 同 noRollbackFor,只是这个地方使用的是类名 |
事务的回滚和不回滚
(1)rollbackFor:参数为class类型的数组,定义哪些异常时回滚;
(2)rollbackForClassName:参数为字符串类型的数组,定义哪些异常时回滚;
(3)noRollbackFor:参数为class类型的数组,定义哪些异常时不回滚;
(4)noRollbackForClassName:参数为字符串类型的数组,定义哪些异常时不回滚。
@Transactional 默认只能回滚RuntimeException和RuntimeException下面的子类抛出的异常,不能回滚Exception异常;如果需要支持回滚Exception异常,需要显示的指明。
如:@Transactional(rollbackFor = Exception.class);
rollbackFor 回滚(预提交) --------》 Exception可替换
- Exception 表示:遇到错误就回滚;
- ServiceException 表示:当ServiceException 失败时,才回滚
- ...
显示的指定rollbackFor注解属性,即使rollbackFor有默认值,但阿里巴巴开发者规范中,还是要求开发者重新指定该参数,因为如果使用默认值,一旦程序抛出了非运行时的其他Exception,事务不会回滚,这会出现很大的bug;
在数据库中操作时:
将数据库变更当作一个事务,整个处理操作完成后,才进行数据库操作,只要里面有一个错误,就失败了。
尤其涉及到多个表的数据库操作时,一定要使用这个注解!!!