一、介绍
@Transactional是spring中常用的注解之一,通常情况下我们在需要对一个service方法添加事务时,加上这个注解,如果发生unchecked exception,就会发生rollback
mybatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。
二、@Transactional 注解的属性信息
三、@Transactional 注解的属性信息用法
当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性
1.当作用在方法级别时会覆盖类级别的定义
2.当作用在接口和接口方法时则只有在使用基于接口的代理时它才会生效,也就是JDK动态代理,而不是Cglib代理
3.当在 protected、private 或者默认可见性的方法上使用 @Transactional 注解时是不会生效的,也不会抛出任何异常
4.默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用。在@Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。
6.以mysql为例,非innodb引擎,例如myisam本身不支持事务,加了@Transactional也不会生效。
7.以mysql为例,非innodb引擎,例如myisam本身不支持事务,加了@Transactional也不会生效。
Throwable分为error和exception,exception分为checked和unchecked(受检异常和非受检异常),其中非受检异常仅包括RuntimeException以及它的子类。
四、@Transactional 注解参数详细解释
参数一: propagation
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务, 则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
参数二:事物超时设置: timeout
默认30秒
参数三:事务隔离级别:isolation
隔离级别是指若干个并发的事务之间的隔离程度,与我们开发时候主要相关的场景包括:脏读取、重复读、幻读。
1、 Isolation 的 Eum 类中定义了“五个”表示隔离级别的值,如下:
Isolation.DEFAULT:使用各个数据库默认的隔离级别【默认】
Isolation.READ_UNCOMMITTED:读取未提交数据(会出现脏读, 不可重复读)(基本不使用)
Isolation.READ_COMMITTED:读取已提交数据(会出现不可重复读和幻读)
Isolation.REPEATABLE_READ:可重复读(会出现幻读)
Isolation.SERIALIZABLE:串行化
2、 在这里,简单解释下什么是“脏读”,“不可重复读”,“幻读”:
脏读:一个事务读取到另一事务未提交的更新数据;
不可重复读: 在同一事务中,多次读取同一数据返回的结果有所不同。换句话说:后续读取可以读到另一事务已提交的更新数据。相反,"可重复读"在同一事务中多次读取数据时,能够保证所读数据一样,也就是后续读取不能读到另一事务已提交的更新数据;
幻读: 一个事务读到另一个事务已提交的 insert 数据;
3、最后,有必要补充一下常用数据库的默认隔离级别:
MYSQL:默认为REPEATABLE_READ
SQLSERVER:默认为READ_COMMITTED
Oracle:默认隔离级别 READ_COMMITTED
注意:mysql数据库,当且仅当引擎是InnoDB,才支持事务(MyIsam引擎不支持事务)
参数四:readOnly(事务读写性)
默认情况下是 false(即:不指定只读性),设置为 true 的含义是: 告诉程序该方法下使用的是只读操作,如果进行其他非读操作,则会跑出异常。
1、 事务的只读性,概念:
从这一点设置的时间点开始(时间点a),到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!!即:查询中不会出现别人在时间点a之后提交的数据。
2、 应用场景:
如果你一次执行单条查询语句,则没有必要启用事务的只读性支持,数据库默认支持SQL执行期间的读一致性;
如果你一次执行多条查询语句,例如统计查询,报表查询。在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态。此时,就有必要启用事务的只读性支持。
【注意】:是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务。
参数五:noRollbackFor 和 noRollbackForClassName(遇到时不回滚)
用来指明不回滚的条件是哪些异常类或者异常类名。
参数六:rollbackFor 和 rollbackForClassName(遇到时回滚)
用来指明回滚的条件是哪些异常类或者异常类名。
Spring默认情况下会对运行期异常(RunTimeException)进行事务回滚,如果遇到checked异常就不回滚。
参数七:value(指定使用的事务管理器)
value 主要用来指定不同的事务管理器,主要用来满足在同一个系统中,存在不同的事务管理器的场景需要。
比如,在Spring中声明了两种事务管理器txManager1,txManager2。然后,用户可以根据需要,修改这个参数来指定特定的txManager。
存在多个事务管理器的情况:在一个系统中,需要访问多个数据源,则必然会配置多个事务管理器。
五、@Transactional 常见的失效场景
@Transactional 应用在非 public 修饰的方法上,不支持回滚;
@Transactional 注解属性 propagation 设置错误;
@Transactional 注解属性 rollbackFor 设置错误;
在同一个类中方法调用,导致 @Transactional 失效;
异常被你的 catch 处理了,导致 @Transactional 没办法回滚而失效;
数据库配置了不支持事务的引擎,或者数据库本身就不支持事务。