spring事务
事务的传播行为
问题: 我们在 A 类的aMethod()
方法中调用了 B 类的 bMethod()
方法。这个时候就涉及到业务层方法之间互相调用的事务问题。如果我们的 bMethod()
如果发生异常需要回滚,如何配置事务传播行为才能让 aMethod()
也跟着回滚呢?
1、PROPAGATION_REQUIRED
(默认传播行为)
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
即当前aMethod有事务就加入aMethod,没有就新建一个事务
2、REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW
修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰
3、NESTED
嵌套式事务,也就是父子的关系,子事务提交依赖于父事务,只有父事务提交之后,子事务才会提交,同样若父事务回滚,子事务也会回滚
4、PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
只读事务
问题:为什么读操作也要事务?
首先要知道事务也会超时的,事务超时指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。原因是由于 MySQL 默认对每一个新建立的连接都启用了autocommit
模式。在该模式下,每一个发送到 MySQL 服务器的sql
语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务,并开启一个新的事务。呢么就是说即使是读操作呢么也是会创建一个事务。
Transactional注解
如果使用了Transactional注解,呢么这个方法的所有sql语句都会在一个事务中执行,但是没有使用的话,sql查询就会在多个事务执行,所以即使是使用读操作,若使用多条查询语句时候,使用Transactional并指出isReadOnly 为true,便会优化执行。
即
- 如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持 SQL 执行期间的读一致性;
- 如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询 SQL 必须保证整体的读一致性,否则,在前条 SQL 查询之后,后条 SQL 查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
Transactional只会在public方法上生效。并且事务也是由代理实现的,呢么调用本类中的事务方法,就需要使用本类的代理
事务失效
1、由于spring中的事务依赖于当前线程内部的ThreadLocal,所以若使用多线程执行同一个事务内部的两个批量sqlsession时候,会导致事务失效,应避免这种做法。
2、由于事务声明式注解Transactional是基于AOP实现的,呢么调用事务方法要使用代理去调用,可以在这个service中注入一个自己的代理,这样由于存在spring的三级缓存,此时循环依赖也会被解决。
例如
@Service
public class OrderService{
@Autowiredprivate OrderService itself;public void saveOrder(Order order){itself.test();}@Transactionalpublic void test(){}}
spring三级缓存为:1、已经实例化且初始化完成的bean 2、实例化但未初始化的bean 3、bean工厂。此处bean的实例化与初始化区别在于,实例化是创建出了这个bean,初始化是我们声明的这个bean中对注入的其他bean进行注入。例如上边的例子,由于三级缓存,创建出OrderService时候,这时候又会去注入OrdersService,虽然这时候OrderService没有初始化完成,但是由于2级缓存存在,所以不会出现循环依赖问题。(若有理解错误,还请指出,谢谢)