一、Spring管理事务的方式:
1.编程式事务(通过代码的方式来实现事务):编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。
2.声明式事务(通过配置的方式来实现事务):声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。
编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。
显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置。
二、Spring中事务的隔离级别
隔离级别 | 含义 |
DEFAULT | 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别. |
READ_UNCOMMITTED | 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 |
READ_COMMITTED | 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 |
REPEATABLE_READ | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 |
SERIALIZABLE | 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别 |
三、Spring中事务的传播行为
事务的传播行为 | 含义 |
REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值) |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务) |
MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常 |
REQUERS_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
NEVER | 以非事务方式运行,如果当前存在事务,抛出异常 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作。 |
四、其他
@Transactional注解的使用
使用步骤:
1.配置事务管理器的bean
2.在业务层使用@Transactional注解 3.配置属性
- isolation:配置事务的隔离级别,默认值是DEFAULT
- proragation:用于指定事务的传播行为,默认是REQUIRED,表示一定有事务,增删改一般使用它,查询的话可以使用SUPPORTS
- read-only:表示指定事务是否只读。默认为false(读写的时候用),查询用true
- time-out:用于指定事务的超时时间,单位为秒,默认-1表示永不过期
- rollback-for:用于指定一个异常,当产生该异常时事务回滚,其他异常不回滚。
- no-rollback-for:用于指定一个异常,当产生该异常时事务不回滚,其他异常回滚。
@Transactional
作用于
- 作用于接口:表明接口所有的实现类都有事务支持
- 作用于类:表明该类的所有方法都有事务支持
- 作用于方法:表明该方法有事务的支持
优先级:接口<类<方法
@Transactional有两点需要注意
只能声明在public的method。原因是spring是通过JDK代理或者CGLIB代理的,生成的代理类,只能处理public方法;
不能被类内部方法调用。还是因为代理的原因,类内部自调用,不会经过代理类,所以@Transactional不会生效
method1调用method2,不会触发method2的@Transactional声明。
在常见的ssm系统里,@Transactional会定义在controller的public方法上,因为一次请求往往意味着一连串的数据库操作,使用事务正好,一旦这次请求成功,则全部commit,一旦失败,则全部rooback。
还要继续深入 @Transactional,简单使用 @Transactional,只是使用默认的参数,不能完全满足业务需求。它含有的参数,是用来设置事务隔离级别和传播特性。
另外:以上参数大多比较好理解。关注点就在于事务的传播特性,当一个拥有事务的方法调用另外一个事务的方法,要理解好传播特性,才不会导致错误的事务处理。比如使用PROPAGATION_REQUIRES_NEW,事务和事务之间是隔离开的,内层事务失败不会影响外层事务。