三、事务五大属性
1、说明
Spring事务属性就是事务的一些基本配置,描述了事务策略如何应用到方法上面,事务属性主要包含以下5个属性
- Spring事务的传播属性
- Spring事务的隔离级别
- Spring事务是否只读
- Spring事务回滚规则
- Spring事务超时时间
2、Spring事务的传播属性
-
**@Transactional(propagation=Propagation.REQUIRED) **
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
-
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
-
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行旧的事务
-
@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
-
@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务执行,否则抛出异常(与Propagation.MANDATORY相反)
-
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他 bean没有声明事务,那就不用事务.
3、Spring事务的隔离级别
-
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
-
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
-
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
-
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化
-
@Transactional(isolation = Isolation.DEFAULT)
默认级别,MYSQL: 默认为REPEATABLE_READ级别 SQLSERVER: 默认为READ_COMMITTED
-
总结
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
大多数的数据库默认隔离级别为 Read Commited,比如 SqlServer、Oracle
少数数据库默认隔离级别为:Repeatable Read 比如: MySQL InnoDB
4、Spring事务超时时间
- TransactionDefinition 接口中定义了1个表示超时时间的常量**TIMEOUT_DEFAULT **,使用getTimeout()方法可以获取到超时时间,单位是秒。Spring事务超时时间,是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在Spring程序中超时时间设置的注解方式是设置timeout的值表示这个事务,true只读取数据但不更新数据,false表示可正常读写数据
- **@Transactional(timeout=30) **默认是-1,不超时
5、Spring事务是否只读
- 事务管理的只读属性是指对事务性资源进行只读操作或者是可读写操作。所谓事务性资源就是指那些被事务管理的资源,如数据源、JMS 资源,以及自定义的事务性资源等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在TransactionDefinition 中以 boolean 类型来表示该事务是否只读,使用方法isReadOnly()来判断事务是否是只读的
6、Spring事务回滚规则
-
@Transactional(rollbackFor=RuntimeException.class)
用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则事务回滚。
-
@Transactional(rollbackForClassName=“RuntimeException”)
用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚
-
@Transactional(noRollbackFor=RuntimeException.class)
用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚
-
@Transactional(noRollbackForClassName=RuntimeException.class)
用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚
四、注解常用参数
参数说明 | 描述 |
---|---|
propagation | @Transactional(propagation=Propagation.REQUIRED) |
Isolation | @Transactional(isolation = Isolation.READ_COMMITTED)读取已提交数据(会出现不可重复读和幻读) |
timeout | @Transactional(timeout=30) |
readOnly | @Transactional(readOnly=true) |
rollbackFor | @Transactional(rollbackFor=RuntimeException.class) 可以指定多个 |
4、事务属性介绍
Spring事务属性定义在TransactionDefinition接口中,Spring中该接口代码实现如下
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
//事务的传播行为
int getPropagationBehavior();
//事务的隔离级别
int getIsolationLevel();
//事务超时时间
int getTimeout();
//是否只读
boolean isReadOnly();
String getName();
}
说明
事务隔离级别
所谓事务的隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,该级别就是 TransactionDefinition.ISOLATION_READ_COMMITTED;
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据,该级别不能防止脏读和不可重复读,因此很少使用该隔离级别;
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是,这将严重影响程序的性能,通常情况下也不会用到该级别。
关于数据库事务并发机制及脏读、不可重复读和幻读等概念的介绍,请移步我的博文《简述数据库事务并发机制》。
(2). 事务传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。TransactionDefinition接口定义了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
这里需要指出的是,以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(如果存在外部事务的话),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。另外,外部事务的回滚也会导致嵌套子事务的回滚。
(3). 事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
- 事务的只读属性
事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition接口中,以 boolean 类型来表示该事务是否只读。
- 事务的回滚规则
通常情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。这通常也是大多数开发者希望的处理方式,也是 EJB 中的默认处理方式。但是,我们可以根据需要人为控制事务在抛出某些未检查异常时任然提交事务,或者在抛出某些已检查异常时回滚事务。