1. 次要的三种流传机制

https://www.cnblogs.com/xzwbl...

REQUIRED、REQUIRES_NEW、NESTED

留神:以下所有的testA()办法与testB()办法是在两个类之中且都讲bean交给spring治理,如非如此会造成事务生效问题请看第二局部

1.1 REQUIRED(默认)

以后没有事务,则新建一个事务,如存在事务,则退出此事务

// 例子// A.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)public void testA() {    insertDataToTableA(dataList);    testB();}// B.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)public void testB(){    insertDataToTableB(dataList);    int i = 1/0;    insertDataToTableC(dataList);}// 后果 testB()退出testA()的事务,testB()产生异样,两个办法均回滚// 如果 testA()不加事务,只有testB()加,则testA()胜利,testB()回滚

1.2 REQUIRES_NEW

创立一个新事务,如果存在以后事务,则挂起该事务。即无论是否已存在事务都新建事务

// 例子// A.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)public void testA() {    insertDataToTableA(dataList);    testB();      int i = 1/0;}// B.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)public void testB(){    insertDataToTableB(dataList);    insertDataToTableC(dataList);}// 后果 testA() 回滚 testB() 胜利,阐明不是一个事物里 

1.3 NESTED

如果以后事务存在,则在嵌套事务中执行(子事务),否则REQUIRED的操作一样(开启一个事务)

这里须要留神两点:

  • 和REQUIRES_NEW的区别
REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而NESTED则是以后存在事务时(咱们把以后事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。
在NESTED状况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW状况下,原有事务回滚,不会影响新开启的事务。
  • 和REQUIRED的区别
REQUIRED状况下,调用方存在事务时,则被调用方和调用方应用同一事务,那么被调用方出现异常时,因为共用一个事务,所以无论调用方是否catch其异样,事务都会回滚
而在NESTED状况下,被调用方产生异样时,调用方能够catch其异样,这样只有子事务回滚,父事务不受影响
// 例子1// A.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)public void testA() {    insertDataToTableA(dataList);    testB();      int i = 1/0;}// B.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)public void testB(){    insertDataToTableB(dataList);    insertDataToTableC(dataList);}// 后果 二者皆回滚,因为是嵌套的父子级事务,所以有一个有问题就都回滚
// 例子2// A.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)public void testA() {    insertDataToTableA(dataList);        try{      testB();    }catch(Exception e){      log.error(e)    }   }// B.class@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)public void testB(){    insertDataToTableB(dataList);    int i = 1/0;    insertDataToTableC(dataList);}// 后果 testA胜利、testB回滚,阐明绝对 REQUIRED 异样能够被捕捉解决

2. 事务生效

2.1 外部调用问题

1. A带事务调B不带事务

// 例0 无异样 -> 两个都能顺利插入表// 例1 B办法异样// 后果 事务失效(A,B专用一个事务),两个办法皆回滚@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)public Integer insertUserInfo() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(5, 'Jack5')");      // 外部调用问题    insertUserInfo2();    return null;}//@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.NESTED)public Integer insertUserInfo2() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(9, 'tom9')");    int i = 1 / 0;    return null;}// 例2 A办法调用完B后再异样 -> 后果雷同事务失效

2. A带事务调B带事务(REQUIRES_NEW)

// 例1 B异样 且 B的流传机制为 REQUIRES_NEW(新建事务)// 后果 B事务失败(追加到A事务里),A,B皆回滚,阐明A,B还是在一个事务里,A办法里异样时同样状况@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)public Integer insertUserInfo() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(5, 'Jack5')");    // 外部调用问题    insertUserInfo2();    return null;}@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRES_NEW)public Integer insertUserInfo2() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(9, 'tom9')");    int i = 1 / 0;    return null;}

3. A带事务调B带事务(NESTED)

// 例1 B异样 且 B的流传机制为 NESTED,在A中捕捉异样// 后果 A事务胜利,B事务失败,异样后仍能插入数据@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)public Integer insertUserInfo() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(5, 'Jack5')");      // 外部调用问题        try {            insertUserInfo2();        }catch (Exception e){            e.printStackTrace();        }    return null;}@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.NESTED)public Integer insertUserInfo2() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(9, 'tom9')");    int i = 1 / 0;    return null;}// 例2 B异样 且 B的流传机制为 NESTED,在A中不捕捉异样// 后果 A,B皆回滚// 例3 A异样 且 B的流传机制为 NESTED,在A中捕捉异样与否都一样// 后果 A,B皆回滚

4. A不带事务调B带事务

// 例0 无异样 -> 两个都能顺利插入表// 例1 B办法异样 -> 事务生效,A,B都不会回滚,都会插入数据// 第一局部中的三种流传机制都会是这种状况//@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)public Integer insertUserInfo() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(5, 'Jack5')");    // 外部调用问题    insertUserInfo2();    return null;}@Transactional(rollbackFor = RuntimeException.class,propagation = Propagation.REQUIRED)public Integer insertUserInfo2() {    jdbcTemplate.execute("INSERT INTO user (id, username) VALUES\n" +            "(9, 'tom9')");    int i = 1 / 0;    return null;}// 例2 A办法调用完B后异样 -> 与例1雷同,事务生效,A,B都不会回滚,都会插入数据

5. 综述

尽量避免外部调用,最多用A带事务调B不带事务,尤其是不能用A不带事务调B带

2.2 外部调用问题事务失败起因

  1. A带事务调B带事务:放在一个代理类里,追加到A的事务,只会代理A,而后this调用B
  2. A不带事务调B带事务:外部调用没走Spring的AOP加强代理机制,也就没做事务加强操作,实质是this实例调用