spring事务传播机制
传播行为 | 含义 | 回滚机制 |
---|---|---|
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在自己的事务中,会启动一个新的事务,如果存在当前事务,在执行期间就会挂起当前事务。 | A->B B报错仅回滚B A报错与B无关 |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中,如果当前有事务运行,会直接抛异常。 | A->B 若A有事务,B压根不会执行(抛异常) |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,就直接抛异常。 | A->B 若A无事务,B压根不会执行(抛异常) |
PROPAGATION_REQUIRED | 这是默认的传播行为。表示当前方法必须运行在事务中,如果当前事务存在,就直接使用这个事务,否则,开启一个新的事务。简单地说就是,如果存在事务,就用该事务,否则就创建一个事务拿来用。 | A->B 若A没有事务,则B新建一个事务,B报错不会导致A回滚 若A有事务,则B加入到A事务,为同一个事务,A、B报错A、B都会回滚 |
ROPAGATION_SUPPORTED | 表示当前方法不需要事务上下文,但如果存在当前事务的话,那么就在这个事务中执行。简单地说,如果存在事务就用,不存在事务就非事务执行。 | 可以大体理解为:这个注解相当于没加 |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中,如果存在当前事务,那么在方法运行期间,会直接挂起当前事务。 | 可以大体理解为:这个注解相当于,注意与REQUIRED区别 |
PROPAGATION_NESTED | 表示如果当前已存在一个事务,那么该方法会嵌套在事务中运行,嵌套的事务可以独立于当前事务单独提交或回滚;如果当前不存在事务,那么就与PROPAGATION_REQUIRED一样。 | 父事务报错会导致子事务回滚 子事务报错父事务不一定回滚(有没有catch,有catch外层不回滚,里层回滚) |
使用误区
疑问点验证
1.调用者存在事务,被调用者无事务注解且抛出异常,会回滚吗?
代码块
SQL
@Transactional(propagation = Propagation.REQUIRED)
public void insert() {
aMapper.insert(new A());
System.out.println("insert a");
b.insert();
}
public void insert() {
bMapper.insert(new B());
System.out.println("insert b");
throw new RuntimeException();
}
揭晓答案
A、B都会回滚
2.调用者存在事务,被调用者无事务注解并且抛出异常且被调用者捕获,会回滚吗?
代码块
SQL
@Transactional(propagation = Propagation.REQUIRED)
public void insertA() {
aMapper.insert(new A());
System.out.println("insert a");
try {
b.insertB();
} catch (Exception e) {
e.printStackTrace();
}
}
public void insert() {
bMapper.insert(new B());
System.out.println("insert b");
throw new RuntimeException();
}
揭晓答案
A、B都不会回滚
3.调用者无事务注解,被调用者存在事务并且抛出异常会回滚吗?
代码块
SQL
public void insertA() {
aMapper.insert(new A());
System.out.println("insert a");
b.insertB();
}
@Transactional(propagation = Propagation.REQUIRED)
public void insertB() {
bMapper.insert(new B());
System.out.println("insert b");
throw new RuntimeException();
}
揭晓答案
A不回滚,B回滚
4.调用者和被调用者都是REQUIRED,被调用者抛出异常,而调用者捕获异常,会回滚吗?
代码块
SQL
@Transactional(propagation = Propagation.REQUIRED)
public void insertA() {
aMapper.insert(new A());
System.out.println("insert a");
try {
b.insertB();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRED)
public void insertB() {
bMapper.insert(new B());
System.out.println("insert b");
throw new RuntimeException();
}
揭晓答案
AB都回滚
5.调用者REQUIRED,被调用者是NESTED,被调用者抛出异常,而调用者捕获异常,会回滚吗?
代码块
SQL
@Transactional(propagation = Propagation.REQUIRED)
public void insertA() {
aMapper.insert(new A());
System.out.println("insert a");
try {
b.insertB();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.NESTED)
public void insertB() {
bMapper.insert(new B());
System.out.println("insert b");
throw new RuntimeException();
}
揭晓答案
A不回滚、B回滚
答案:a、b都不回滚
结论:如果当前函数中主动捕获异常就不会回滚,如果被spring捕获就回滚