一、概念
首先事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务有 Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)四种特性,简称ACID四特性。
- 原子性
事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
- 隔离性
指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
- 持久性
指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
二、Transactional注解原理
spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。
三、Transactional使用方法
@Transactional注解的可用参数
1.readOnly
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false
🌰@Transactional(readOnly=true/false)
2.rollbackFor
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。
🌰@Transactional(rollbackFor=RuntimeException.class) 或者
@Transactional(rollbackFor={RuntimeException.class, BaseAppException.class})
3.rollbackForClassName
该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。
🌰@Transactional(rollbackForClassName="RuntimeException")或者
@Transactional(rollbackForClassName={"RuntimeException","BaseAppException"})
4.noRollbackFor
该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚
🌰@Transactional(noRollbackFor=RuntimeException.class) 或者
@Transactional(noRollbackFor={RuntimeException.class, BaseAppException.class})
5.noRollbackForClassName
该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则不进行事务回滚。
🌰@Transactional(noRollbackForClassName="RuntimeException")或者
@Transactional(noRollbackForClassName={"RuntimeException","BaseAppException"})
6.timeout
该属性用于设置事务的超时秒数,默认值为-1表示永不超时
🌰@Transactional(timeout=10)
7.propagation
该属性用于设置事务的传播行为, Spring在TransactionDefinition接口中规定了7种类型的事务传播行为
🌰@Transactional(propagation=Propagation.REQUIRED)
事务传播行为类型 | 说明 |
---|---|
REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
8.isolation
🌰@Transactional(isolation=Isolation.READ_UNCOMMITTED)
该属性用于设置底层数据库的事务隔离级别
事务隔离级类型 | 说明 |
DEFAULT | 默认值 |
READ_UNCOMMITTED | 读取未提交数据(会出现脏读, 不可重复读) 基本不使用 |
READ_COMMITTED | 读取已提交数据(会出现不可重复读和幻读) |
REPEATABLE_READ | 可重复读(会出现幻读) |
SERIALIZABLE | 串行化 |
- 脏读 : 一个事务读取到另一事务未提交的更新数据
- 不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
- 幻读 : 一个事务读到另一个事务已提交的insert数据
四、总结
@Transactional注解可以作用于接口、接口方法、类以及类方法上 。
1. 当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性 。
2. 当作用在方法级别时会覆盖类级别的定义 。
3. 当作用在接口和接口方法时则只有在使用基于接口的代理时它才会生效,也就是JDK动态代理,而不是Cglib代理 。
4. 当在 protected、private 方法上使用 @Transactional 注解时是不会生效的,也不会抛出任何异常 。
5. 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的事务方法时不会开启事务。
五、参考
https://segmentfault.com/a/1190000013341344
https://www.cnblogs.com/happy4java/p/11206804.html
来源:oschina
链接:https://my.oschina.net/kimyeongnam/blog/3188541