@Transactional
-----------------------------------------------------------------------------------------------------------------------------
通过AOP,在方法执行时控制事务
事务基本要素
原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
一致性(Consistency): 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
隔离性(Isolation): 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
持久性(Durability): 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
用法:
- 需要回滚不要在测试方法上使用@Rollback,用@Transactional即可
- 如果采用了读写分离配置,那么千万不要在测试查询的方法上加回滚事务标记,否则只会经过写库
- 无论从规范角度还是实际结果角度,@Transactional标记一定不要偷懒标注在实现类上,一来会影响查询的效率,二来有时会不能回滚。因此都注解在方法上错不了,或者采用aop统一拦截
属性:
1.propagation 属性(事务的传播行为)
- 默认:Propagation.REQUIRED:多个事务合并为一个事务,一个报错全部回滚。
- Propagation.SUPPORTS:存在事务则加入,没有事务则以非事务方式继续运行
- Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
- Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。
- Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。
- Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。
- Propagation.NESTED:和 Propagation.REQUIRED 效果一样。
2.isolation 属性(事务的隔离性)
- 默认:Isolation.DEFAULT:表示使用底层数据库的默认隔离级别
- Isolation.READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
- Isolation.READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- Isolation.REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
- Isolation.SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
3.timeout 属性
-
事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
4.readOnly 属性
-
指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
5.rollbackFor 属性
-
用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
6.noRollbackFor 属性
-
抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。
----------------------------------------------------------------------------------------------------
->需要控制的关键业务必须加,还要准确测验异常,回滚!
->不要再接口上加,在具体类上加!
->不要贪图省事放在类级的声明中,@Transactional会降低性能,具体类具体实施属性
->不要用在调用多个类的方法中,会使注解无效
->使用了@Transactional的方法,只能是public
->spring的事务在抛异常的时候会回滚,如果是catch捕获了,事务无效。可以在catch里面加上throw new RuntimeException();
->使用synchronized锁的范围大于事务控制的范围,把synchronized加到Controller层或者大于事务边界的调用层!
来源:CSDN
作者:suzhou_xj
链接:https://blog.csdn.net/suzhou_xj/article/details/103688939