實踐出真知--Spring 事務(wù)傳播行為

Transactional#Propagation事務(wù)傳播行為

事務(wù)傳播行為用來描述由某一個事務(wù)傳播行為修飾的方法被嵌套進另一個方法時事務(wù)如何傳播

一直對這7種傳播行為記得不是特別清楚,也容易混淆,本文通過具體的例子來驗證一下,每一種事務(wù)傳播行為的實際效果。

tip: 參數(shù)String method是為了一次運行多個單元測試方法,可以直接從數(shù)據(jù)庫知道哪個方法成功了

REQUIRED

@Transactional默認行為

在外圍方法未開啟事務(wù)的情況下Propagation.REQUIRED注解的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。

外圍方法開啟事務(wù)的情況下Propagation.REQUIRED注解的內(nèi)部方法會加入到外圍方法的事務(wù)中,所有Propagation.REQUIRED修飾的內(nèi)部方法和外圍方法均屬于同一事務(wù),只要一個方法回滾,整個事務(wù)均回滾。

/**
 * @createDate:2019/6/14$14:02$
 * @author: Heyfan Xie
 */
@Service
public class RequiredService {

    private static final String TYPE = "required";

    @Autowired
    private RequiredUser1Service user1Service;

    @Autowired
    private RequiredUser2Service user2Service;


    /**
     * 外圍方法沒有事務(wù)
     *      調(diào)用有事務(wù)的方法1
     *      調(diào)用有事務(wù)的方法2
     * 外圍方法拋出異常
     * ------------------
     * 結(jié)果:
     * 方法1執(zhí)行成功
     * 方法2執(zhí)行成功
     */
    public void notransactionExceptionRequiredRequried() {
        user1Service.addRequried(TYPE + 1);
        user2Service.addRequried(TYPE + 1);
        throw new RuntimeException();
    }


    /**
     * 外圍方法沒有事務(wù)
     *      調(diào)用有事務(wù)的方法1
     *      調(diào)用有事務(wù)的方法2
     *          方法2拋出異常
     * ------------------
     * 方法1執(zhí)行成功
     * 方法2執(zhí)行回滾
     */
    public void notransactionequiredRequriedException() {
        user1Service.addRequried(TYPE + 2);
        user2Service.addRequriedException(TYPE + 2);
    }

    /**
     * 外圍方法有事務(wù)
     *      調(diào)用有事務(wù)的方法1
     *      調(diào)用有事務(wù)的方法2
     * 外圍方法拋出異常
     * ------------------
     * 方法1執(zhí)行回滾
     * 方法2執(zhí)行回滾
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void transactionExceptionRequiredRequired(){
        user1Service.addRequried(TYPE + 3);
        user2Service.addRequried(TYPE + 3);
        throw new RuntimeException();
    }

    /**
     * 外圍方法有事務(wù)
     *      調(diào)用有事務(wù)的方法1
     *      調(diào)用有事務(wù)的方法2
     *          方法2拋出異常
     * ------------------
     * 方法1執(zhí)行回滾
     * 方法2執(zhí)行回滾
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void transactionRequiredRequiredException(){
        user1Service.addRequried(TYPE + 4);
        user2Service.addRequriedException(TYPE + 4);
    }


    /**
     * 外圍方法有事務(wù)
     *      調(diào)用有事務(wù)的方法1
     * try
     *      調(diào)用有事務(wù)的方法2
     *          方法2拋出異常
     * catch
     * ------------------
     * 方法1執(zhí)行回滾
     * 方法2執(zhí)行回滾
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void transactionRequiredRequiredExceptionTry(){
        user1Service.addRequried(TYPE + 5);
        try {
            user2Service.addRequriedException(TYPE + 5);
        } catch (Exception e) {
            System.out.println("方法回滾");
        }
    }
}

@Service
public class RequiredUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequried(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class RequiredUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequried(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public void addRequriedException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}
序號 驗證方法 USER1 USER2 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 成功 成功 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),外圍方法拋出異常不會影響到調(diào)用方法的的事務(wù),所以都能成功
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 回滾 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),方法2拋出異常只會回滾本身的事務(wù)。
3 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 回滾 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required,所以都會加入到外圍事務(wù),全部都會回滾
4 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 回滾 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required,所以都會加入到外圍事務(wù),全部都會回滾
5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 回滾 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required,所以都會加入到外圍事務(wù),全部都會回滾,由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only

SUPPORTS

存在事務(wù),就加入到事務(wù)中;不存在事務(wù),就不創(chuàng)建自己的事務(wù)。

在外圍方法未開啟事務(wù)的情況下,Propagation.SUPPORTS注解的的方法會以無事務(wù)的方式運行。

在外圍方法開啟事務(wù)的情況下,Propagation.SUPPORTS注解的方法會加入當(dāng)前事務(wù)。

@Service
public class SupportUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.SUPPORTS)
    public void addSupport(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class SupportUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.SUPPORTS)
    public void addSupport(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.SUPPORTS)
    public void addSupportException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}
序號 驗證方法 USER1 USER2 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 成功 成功 外圍方法沒有事務(wù),內(nèi)部的方法1,方法2以無事務(wù)的方式運行,所以拋出異常不會回滾
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 成功 外圍方法沒有事務(wù),內(nèi)部的方法1,方法2以無事務(wù)的方式運行,所以拋出異常不會回滾
3 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 回滾 回滾 外圍方法有事務(wù),內(nèi)部的方法1,方法2加入外圍事務(wù)的方式運行,所以外圍方法拋出異常會回滾
4 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 回滾 回滾 外圍方法有事務(wù),內(nèi)部的方法1,方法2加入外圍事務(wù)的方式運行,所以方法2拋出異常會回滾
5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 回滾 回滾 外圍方法有事務(wù),內(nèi)部的方法1,方法2加入外圍事務(wù)的方式運行,所以方法2拋出異常會回滾;由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only

MANDATORY

只能運行在一個已經(jīng)存在的事務(wù)中,不能自己創(chuàng)建事務(wù)

在外圍方法未開啟事務(wù)的情況下,Propagation.MANDATORY注解的方法運行時會拋出錯誤:No existing transaction found for transaction marked with propagation 'mandatory'

在外圍方法開啟事務(wù)的情況下,Propagation.MANDATORY注解的方法會加入當(dāng)前事務(wù)。

@Service
public class MandatoryUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.MANDATORY)
    public void addMandatory(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class MandatoryUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.MANDATORY)
    public void addMandatory(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.MANDATORY)
    public void addMandatoryException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}
序號 驗證方法 USER1 USER2 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 直接報錯 No existing transaction found for transaction marked with propagation 'mandatory'
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 直接報錯 No existing transaction found for transaction marked with propagation 'mandatory'
3 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 回滾 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是MANDATORY,2個方法會加入已有的外圍創(chuàng)建的事務(wù),外圍方法的異常會導(dǎo)致方法1、方法2回滾
4 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 回滾 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是MANDATORY,2個方法會加入已有的外圍創(chuàng)建的事務(wù),方法2的異常會導(dǎo)致方法1、方法2回滾
5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 回滾 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),所以方法1能成功,方法2拋出了異常就回滾了;由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only

REQUIRES_NEW

不管當(dāng)前是否已經(jīng)存在事務(wù),都會新建一個事務(wù)

在外圍方法未開啟事務(wù)的情況下,Propagation.REQUIRES_NEW注解的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。

在外圍方法開啟事務(wù)的情況下,Propagation.REQUIRES_NEW注解的內(nèi)部方法依然會單獨開啟獨立事務(wù),且與外部方法事務(wù)也獨立,內(nèi)部方法之間、內(nèi)部方法和外部方法事務(wù)均相互獨立,互不干擾。

外圍方法調(diào)用方式與REQUIRED一致,只是內(nèi)部方法的注解改為了REQUIRES_NEW
@Service
public class RequiredNewUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequriedNew(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class RequiredNewUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequriedNew(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addRequriedNewException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}
序號 驗證方法 USER1 USER2 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 成功 成功 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),外圍方法拋出異常不會影響到調(diào)用方法的的事務(wù),所以都能成功
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 回滾 外圍沒有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),方法2拋出異常只會回滾本身的事務(wù)。
3 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 成功 成功 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),外圍方法的異常不會影響方法1、方法2,所以都能成功
4 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),所以方法1能成功,方法2拋出了異異常就回滾了
5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 成功 回滾 外圍有開啟事務(wù),調(diào)用的方法分別在獨立的自己的事務(wù)內(nèi),因為是required_new,都會加入到新的的事務(wù),所以方法1能成功,方法2拋出了異常就回滾了;由于捕獲了異常但是沒有拋出,會報錯: Transaction silently rolled back because it has been marked as rollback-only

NOT_SUPPORTED

當(dāng)前方法不應(yīng)該有事務(wù),如果有事務(wù)存在,將它掛起,以無事務(wù)狀態(tài)運行

不管外圍方法是否有事務(wù),NOT_SUPPORT都會以無事務(wù)的方式運行

外圍方法調(diào)用方式與REQUIRED一致,只是內(nèi)部方法的注解改為了NOT_SUPPORTED
@Service
public class NotSupportUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addNotSupport(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class NotSupportUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addNotSupport(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addNotSupportException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}
序號 驗證方法 USER1 USER2 分析
1 5個驗證方法 成功 成功 不管外圍方法是否有事務(wù),內(nèi)部的方法1,方法2都會以無事務(wù)的方式運行,所以拋出異常不會回滾

NEVER

注釋的業(yè)務(wù)方法絕對不能在事務(wù)中運行,否則拋出異常

在外圍方法未開啟事務(wù)的情況下,Propagation.NEVER注解的內(nèi)部方法會以無事務(wù)的方式運行。

在外圍方法開啟事務(wù)的情況下,Propagation.NEVER注解的內(nèi)部方法會因為不能加入到事務(wù)中,拋出異常Existing transaction found for transaction marked with propagation 'never'

@Service
public class NeverUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.NEVER)
    public void addNever(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class NeverUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.NEVER)
    public void addNever(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.NEVER)
    public void addNeverException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}
序號 驗證方法 USER1 USER2 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 成功 成功 外圍沒有開啟事務(wù),調(diào)用的方法1,方法2都以無事務(wù)方式運行,外圍方法拋出異常不會回滾
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 成功 外圍沒有開啟事務(wù),調(diào)用的方法1,方法2都以無事務(wù)方式運行,方法2拋出異常不會回滾
3,4,5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 拋出異常 外圍有開啟事務(wù),因為是NEVER,無法在已存在的事務(wù)中運行,會拋出和異常:Existing transaction found for transaction marked with propagation 'never'

NESTED

在當(dāng)前事務(wù)上開啟一個子事務(wù)(Savepoint),如果提交主事務(wù)。那么連同子事務(wù)一同遞交。如果提交子事務(wù)則保存點之前的所有事務(wù)都會被遞交;如果當(dāng)前不存在事務(wù),就按REQUIRED方式

外圍方法沒有開啟事務(wù),Propagation.NESTED注解的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。

外圍方法開啟事務(wù),Propagation.NESTED注解的內(nèi)部方法會在已存在的事務(wù)中開啟一個子事務(wù),拋出子事務(wù)的方法拋出異??梢员煌鈬椒ú东@,不會影響主事務(wù);而外圍方法的主事務(wù)回滾卻會導(dǎo)致子事務(wù)也會回滾(與requried不同的是:nested的異常被捕獲了不會影響外層方法的事務(wù)。)。

@Service
public class NestedUser1Service {

    @Autowired
    private User1Repository user1Repository;

    @Transactional(propagation = Propagation.NESTED)
    public void addNested(String method) {
        User1 user = new User1();
        user.setName(method + "張三");
        user1Repository.save(user);
    }
}
@Service
public class NestedUser2Service {

    @Autowired
    private User2Repository user2Repository;

    @Transactional(propagation = Propagation.NESTED)
    public void addNested(String method) {
        User2 user = new User2();
        user.setName(method + "李四");
        user2Repository.save(user);
    }


    @Transactional(propagation = Propagation.NESTED)
    public void addNestedException(String method) {
        User2 user = new User2();
        user.setName(method + "王五");
        user2Repository.save(user);
        throw new RuntimeException();
    }
}

如果按照上面的那種通過jpa的方式,當(dāng)外圍方法有事務(wù)的時候,運行會報錯:JpaDialect does not support savepoints - check your JPA provider's capabilities
意思是通過jpa的方式不支持savepoints,
所以需要通過JdbcTemplte的方式運行,
這里另起了一個項目,spring boot 集成jdbc來測試:

@Service
public class NestedUser1Service {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.NESTED)
    public void addNested(String method) {
        String name = method + "張三";
        jdbcTemplate.execute("insert into user1(name) values('" + name + "')");
    }
}
@Service
public class NestedUser2Service {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.NESTED)
    public void addNested(String method) {
        String name = method + "李四";
        jdbcTemplate.execute("insert into user2(name) values('" + name + "')");
    }


    @Transactional(propagation = Propagation.NESTED)
    public void addNestedException(String method) {
        String name = method + "李四";
        jdbcTemplate.execute("insert into user2(name) values('" + name + "')");
        throw new RuntimeException();
    }
}

增加一個插入USER3在外層方法上,來驗證回滾的范圍,同時在所有的sql運行之后加入一行日志打印,指示插入操作是否執(zhí)行了。

第一種方式:插入USER3在方法1方法2之后 (在最開頭REQUIRED中的5種調(diào)用方式都按這種方式加入USER3的保存方法)

   @Autowired
    private JdbcTemplate jdbcTemplate;

    public void notransactionExceptionNotSupportNotSupport() {
        user1Service.addNested(TYPE + 1);
        user2Service.addNested(TYPE + 1);

        String name = TYPE + "1王五";
        jdbcTemplate.execute("insert into user3(name) values('" + name + "')");
        System.out.println("USER3 插入執(zhí)行成功");
        throw new RuntimeException();
    }
序號 驗證方法 user1 user2 USER3 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 成功 成功 成功 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 回滾 拋出異常沒有運行 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行;由于USER3是異常之后,沒有運行到。
3 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 回滾 回滾 回滾 外圍方法的異常會回滾nested注解的事務(wù)
4 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 回滾 回滾 拋出異常沒有運行 方法2拋出異常回滾到該子事務(wù)設(shè)置的保存點,然后異常往上拋出到外層方法,所以導(dǎo)致方法1回滾了,由于USER3是異常之后執(zhí)行,沒有運行到。
5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 成功 回滾 成功 方法2拋出異常只回滾到該子事務(wù)設(shè)置的保存點,然后異常拋出后被捕獲了,所以不會影響外層方法和方法1的結(jié)果

第二種方式:插入USER3在方法1方法2 之前 (在最開頭REQUIRED中的5種調(diào)用方式都按這種方式加入USER3的保存方法)

   @Autowired
    private JdbcTemplate jdbcTemplate;

    public void notransactionExceptionNotSupportNotSupport() {
        String name = TYPE + "1王五";
        jdbcTemplate.execute("insert into user3(name) values('" + name + "')");
        System.out.println("USER3 插入執(zhí)行成功");

        user1Service.addNested(TYPE + 1);
        user2Service.addNested(TYPE + 1);

        throw new RuntimeException();
    }
序號 驗證方法 user1 user2 USER3 分析
1 外圍方法沒有事務(wù),調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2,外圍方法拋出異常 成功 成功 成功 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行
2 外圍方法沒有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 成功 回滾 成功 外圍沒有事務(wù),內(nèi)部按照REQUIRED運行
3 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,外圍方法拋出異常 回滾 回滾 回滾 外圍方法的異常會回滾nested注解的事務(wù)
4 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常 回滾 回滾 回滾 方法2拋出異?;貪L到該子事務(wù)設(shè)置的保存點,然后異常往上拋出到外層方法,所以導(dǎo)致外層方法和方法1都回滾了
5 外圍方法有事務(wù), 調(diào)用有事務(wù)的方法1,調(diào)用有事務(wù)的方法2 ,方法2拋出異常,外圍方法捕獲異常 成功 回滾 成功 方法2拋出異常只回滾到該子事務(wù)設(shè)置的保存點,然后異常拋出后被捕獲了,所以不會影響外層方法和方法1的結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 首先,說大概說一下事務(wù)傳播行為,隨后講事務(wù)失效,具體分析同一個類里方法調(diào)用造成事務(wù)失效的情況,再到事務(wù)傳播行為應(yīng)該...
    西部小籠包閱讀 6,809評論 1 8
  • 什么是事務(wù) 事務(wù)就是一組操作數(shù)據(jù)庫的動作集合。 動作集合被完整地執(zhí)行,我們稱該事務(wù)被提交。動作集合中的某一部分執(zhí)行...
    超級變換形態(tài)閱讀 765評論 0 6
  • 事務(wù),是為了保障邏輯處理的原子性、一致性、隔離性、永久性。 通過事務(wù)控制,可以避免因為邏輯處理失敗而導(dǎo)致產(chǎn)生臟數(shù)據(jù)...
    uzip柚子皮閱讀 4,808評論 3 16
  • 事務(wù)的嵌套概念 所謂事務(wù)的嵌套就是兩個事務(wù)方法之間相互調(diào)用。spring事務(wù)開啟 ,或者是基于接口的或者是基于類的...
    jackcooper閱讀 1,499評論 0 10
  • 最近朋友情緒低落的人數(shù)有點多,我則到處聽他們訴說,傾訴,哎……我只能作為朋友的角度多勸勸他們,試著讓他們情緒好受一點。
    漫步奮斗路閱讀 98評論 0 0

友情鏈接更多精彩內(nèi)容