事务相关基础解析
- 事务分类:
- 物理事务
- 逻辑事务
- 物理事务与逻辑事务的区别:
- 最大差别在于事务传播行为
- 什么是事务传播行为:
- 用于指定下多个事务方法间调用时,事务是如何在这些方法间传播的
事务传播方法解析
方法A:
@Service
public class A {
@Autowired
private B b;
@Transactional(propagation=Propagation.XXX)
public void save() {
// ...
b.save();
// ...
}
}
方法B:
@Service
public class B {
@Transactional(propagation=Propagation.XXX)
public void save() {
// ...
}
}
REQUIRED 级别
- Spring 默认的事务传播级别
- 特点:
- 当前上下文已存在事务,则加入到事务中执行
- 当前上下文不存在事务,则新建事务执行。
SUPPORTS 级别
- 特点:
- 支持事务:b.save() 在事务环境中运行,则以事务形式运行
- 支持非事务:b.save() 在非事务环境中运行,则以非事务形式运行
注:
- 所谓的非事务形式的数据库访问只是指没有显式的事务边界,即数据库操作只是 auto-commit 的方式,在数据库的物理事务概念上,还是有事务的。
- 非事务环境中运行:a.save() 调用 b.save() 时,a 是非事务执行(非手动提交事务,而是auto-commit);那么 b.save() 在执行前,a.save() 的物理事务就要先提交;此时 b.save() 的物理事务也是 auto-commit;这样才是这里说的 b.save() 以非事务方法运行,而不是指b.save() 不开启数据库物理事务。
- 事务环境中运行:a.save() 调用 b.save() 时;b 的外层 a.save() 本身是手动提交事务时,b.save() 也会包含在 a.save() 里边的同一个事务去执行,也就是说a.save()与b.save()的SQL操作在同一个物理事务中。
MANDATORY 级别
- 特点:
- b.save() 只能在已有的事务的方法中被调用,否则会抛异常。
REQUIRES_NEW 级别
- 特点:
- 总是会创建一个新事务(包括物理事务);
- 每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行
- 两个方法之间既不属于同一个逻辑事务也不属于同一个物理事务。
NOT_SUPPORTED
- 特点:
- 不支持事务
- 当处于存在事务的上下文环境中运行时,b.save() 会暂停当前已开启的事务,意味着 a.save() 的事务被挂起直至 b.save() 以非事务方法运行完毕后,a.save() 的事务继续执行。
NEVER
- 特点:
- 绝不能在事务环境中运行,
- 如果 a.save() 里声明了使用事务,而 b.save() 的事务类型声明为never,那么只能以抛异常告终。
- 与Mandatory相反,Mandatory意思是强制要求上下文中有事务(外层有事务),否则抛异常,而Never是上下文中不能有事务(外层无事务),否则抛异常。
NESTED
-
特点:
- 嵌套事务支持。
- 该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。
-
Nested和RequiresNew的区别:
- RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而RequiresNew由于都是全新的事务,所以之间是无关联的
- Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务
使用嵌套事务,必须确保具体事务管理器实现的nestedTransactionAllowed属性为true,否则不支持嵌套事务,如DataSourceTransactionManager默认支持,而HibernateTransactionManager默认不支持,需要我们来开启。