Spring 框架中对于事物的管理,主要定义了一下四种属性:
- 事物的隔离(Isolation)级别
- 事物的传播行为(Propagation Behavior)
- 事物的超时时间(TImeout)
- 是否为只读(ReadOnly)
事物的隔离级别又有以下5个常量用于标志可供选择的隔离级别:
- ISOLATION_DEFAULT:如果指定隔离级别为 ISOLATION_DEFAULT,则表示使用数据库默认的隔离级别,通常情况下是 Read Committed。
- ISOLATION_READ_UNCOMMITTED:对应 Read Uncommitted 隔离级别,无法避免脏读,不可重复读和幻读。
- ISOLATION_READ_COMMITTED:对应 Read Committed 隔离级别,可以避免脏读,但无法避免可重复读和幻读。
- ISOLATION_REPEATABLE_READ:对应 Repeatable Read 隔离级别,可以避免脏读和不可重复读,但不能避免幻读。
- ISOLATION_SERIALIZABLE:对应 Serialization 隔离级别,可以避免所有的脏读,不可重复读以及幻读,但并发性效率最低。
事物的传播行为,有以下7种:
- PROPAGETION_REQUIRED:如果当前存在一个事务,则加入当前事务。如果不存在任何事务,则创建一个新的事务。总之,要至少保证在一个事务中运行。Required 通常作为默认的事务传播行为。
- PROPAGETION_SUPPORTS:如果当前存在一个事务,则加入当前事务。如果当前不存在事务,则直接执行。对于一些查询方法来说,那么不需要事务的支持。如果当前方法被其他方法调用,而其他方法启动了一个事务,使用 Supports 可以保证当前方法能够加入当前事务,并洞察当前事务对数据资源所做的更新。
- PROPAGETION_MANDATORY:mandatory 强制要求当前存在一个事务,如果不存在,则抛出异常。如果某个方法需要事务支持,但自身又不管理事务提交或者回滚,那么比较适合使用 mandatory。
- PROPAGETION_REQUIRES_NEW:不管当前是否存在事务,都会创建新的事务。如果当前存在事务,会将当前事务挂起(Suspend)。如果某个业务对象所做的事务不想影响到外层事务, requires_new 应该是合适的选择。比如,假设当前的事务方法需要向数据库中更新写日志信息,但是指这些日志信息更新失败,我们也不想因为该业务方法的事务回滚,而影响到外层事务的成功提交。因为这种情况下,当前业务方法的事务成功与否对外层事务来说无关紧要。
- PROPAGETION_NOT_SUPPORTED:不支持当前事务,而是在没有事务的情况下执行。如果当前存在事务的话,当前事务原则上将被挂起(Suspend)。
- PROPAGETION_NEVER:永远不需要当前存在事务,如果存在事务,则抛出异常。
- PEOPAGETION_NESTED:如果存在当前事务,则在当前事务的一个嵌套事务中执行,否则与 PROPAGETION_REQUIRED 的行为类似,即创建新的事务,在新创建的事务中执行。Nested 粗看起来好像与 PROPAGETION_REQUIRES_NEW 创建的新事务与外层事务属于同一个 “档次”,即二者的地位是相同的。当新创建的事务运行的时候,外层事务将被暂时挂起。而 Nested 创建的嵌套事务则不然,它是寄生于当前外层事务的,它的地位比当前外层事务的地位要小一号。当内部嵌套事务运行的时候,外层事务也是出于 active 状态,如下图涉及的多个事务相互之间的地位。
注意:
1. REQUIRES_NEW 传播行为中,外层事务抛出异常,不会影响内部事务。外部事务的异常会影响外层事务。
2. MyBatis 不支持 NESTED 传播行为,最好不使用。