前言
有一段时间没有更新记录了,正好今天是周五。公司给的一个小项目里面有自己封装的框架,闲暇时光看一看…
无意之中看到了封装分页的的底层方法中使用了这样的注解。
1 | ( |
那我就顺便学习,总结下@Transactional
注解当中propagation
属性的一些用法和特征吧,充充电。
看看源码
@Transactional有哪些属性呢
在Spring
的事务管理当中,我们一直都是使用@Transactional
注解来对事务进行设定的。简而言之,在类或者方法上使用@Transactional
注解,并且传输属性获得相应的Transaction特性。Spring
当中对于@Transactional
注解的属性从源码查看如下:
1 | ({ElementType.METHOD, ElementType.TYPE}) |
从源码当中可以看出@Transactional
有propagation
isolation
timeout
readOnly
rollbackForClassName
noRollbackForClassName
等属性。
isolation
是设置事务隔离,timeout
事务超时,readOnly
定义该事务的方法只读,默认为false,rollbackForClassName
定义回滚条件,比如发生RuntimeException
时候发生回滚,noRollbackForClassName
不回滚,有些异常时正常情况,不进行回滚。通过这些属性可以定义出满足复杂应用事务的要求。
具体看看propagation属性
在Service层类上使用@Transactional
注解,声明这个类所有方法需要事务管理,每一个业务方法开始时候都会打开一个事务,每一个方法所需要的事物管理级别特性的不同,就需要我们使用 @Transactional
当中这些属性来操作了。
Spring
默认情况下是对RuntimeException
运行期异常进行事务回滚,并且只对于运行时异常当中的unchecked
异常回滚,对于checked
异常就不回滚,对于checked
unchecked
异常分类不在这里记录,之后再进行记录。
上面说到默认对运行时异常当中的unchecked
异常进行回滚,那么问题来了,我们想要实现对checked
异常进行回滚怎么办呢?当然有方法可以处理的,就需要使用到上面说到的属性。
- 让
checked
异常回滚
1 | (rollbackFor = Exception.class) |
- 让
unchecked
异常不回滚
1 | (noRollbackFor = RuntimeException.class) |
- 查询操作不需要事务
1 | (propagation = Propagation.NOT_SUPPORTED) |
或者
1 | true) (propagation = Propagation.NOT_SUPPORTED,readOnly = |
将这个方法做成了一个只读事务,提高效率。
说了这么多还不知道Propagation
是个什么东西呢,这是一个枚举类型,里面定义了该属性的各种意义:
1 | public enum Propagation { |
Propagation的各枚举含义
上面已经将Propagation
当中各个枚举列举出来了,它们都是什么含义呢?
- REQUIRED(必须)
业务方法需要在一个容器当中运行。如果该方法运行时候已经处在一个事务中,那么加入该事务,否则自己新建事务。
这个是默认值
- SUPPORTS(支持)
如果业务方法在某个事务范围内被调用,则成为该事务的一部分。如果该业务方法在事务范围之外被调用,则在没有事务环境下运行。(有则改之无则加勉,有则用之无则不用)
- MANDATORY(强制性)
业务方法只能在一个已经存在的事物当中执行,不能够自己发起事务。如果该业务方法在没有事务环境下运行则会抛出异常(IllegalTransactionStateException
)。
- REQUIRES_NEW(需要新的)
不管事务是否存在,该业务方法都会自己新建一个新的事务。如果业务方法已经运行在一个事务当中,则原来的事务被挂起,新事务被创建。
- NOT_SUPPORTED
业务方法不需要事务。如果该业务方法运行没有关联到事务,则不会为其开启事务;如果该业务方法在一个事务当中被调用,该事务被挂起,调用结束后,原先事务恢复执行。
- NEVER
业务方法绝对不能再事务范围内执行。如果在就抛出异常(IllegalTransactionStateException
)。只有不关联任务事务才正常执行。
- NESTED
业务方法执行时存在一个活动的事务,那么该方法运行在一个嵌套的事务当中,作为子事务。如果没有活动事务则按照REQUIRED
属性来执行。该属性使用一个单独的事务,拥有很多个可以回滚的保存点,内部事务的回滚不会对外部事务造成影响。
举个栗子吧
上面说了这么多了,下面举个栗子,说一下吧。
1 |
|
先上一段伪代码。在Service
层定义两个方法,分别为internalMethod
和 externalMetod
。然后里面都调用exampleDao
当中的doSomething()
方法。下面就来根据上面列举出来的Propagation
的属性来讨论事务。
Propagation属性 | externalMethod | internalMethod |
---|---|---|
Propagation.REQUIRED(默认 ) |
此时无事务,新开始一个事务并在其中运行 | 在externalMethod 方法的事务中运行 |
Propagation.SUPPORTS | externalMethod 无事务,不在事务中运行 |
加入externalMethod 事务中运行 |
Propagation.MANDATORY | 抛出异常 | 在externalMethod 事务中运行 |
Propagation.REQUIRES_NEW | 新开启事务并在其中运行 | 挂起externalMethod 中事务,直至internalMethod 中新开事务运行完毕 |
Propagation.NOT_SUPPORTED | externalMethod 无事务,不在事务中运行 |
挂起externalMethod 中事务,直至internalMethod 方法执行完毕(注意这里不是事务,是方法) |
Propagation.NEVER | externalMethod 无事务,不在事务中运行 |
抛出异常(不能在事务中运行) |
下回就统计统计上面说到的unchecked
checked
异常吧。
联系
聪聪的独立博客 ,一个喜欢技术,喜欢钻研的95后。如果你看到这篇文章,千里之外,我在等你联系。