Spring 外层事务失败回滚内层事务

Spring outer transaction failure roll back inner transaction

我有以下使用 Spring @Transactional 注释的代码。

//in A.java
Class A {
    @Transactional(propagation=propagation.???)
    public void aMethod() {
        B b = new B();
        b.bMethod(); // success and committed
        aPrivateMethod(); // failure
    }

    private void aPrivateMethod() { //something }
}

//in B.java
Class B {
    @Transactional(propagation=propagation.???)
    public void bMethod() { //something }
}

我期望 A.aMethod() 的行为是:

If b.bMethod() succeeds and has committed but aPrivateMethod() fails, then A.aMethod() is rolled back including b.bMethod().

如何设置@Transactional 传播参数来实现此目的?

结论是这样的。

示例 1

// A.java
class A {
    @Transactional(rollbackFor = Exception.class)
    public void aMethod() {
        B b = new B();
        try {
            b.bMethod("111", false); // bMethod() is NOT rolled back, record of "111" has been created
        } catch (Exception e) {
            // Do nothing, let it go
        }
        b.bMethod("222", true); // record of "222" has been created
    }

    // The annotation below is ignored
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void bMethod(String id, bool success) {
        createRecordInDB(id);
        if (!success) {
            throw new Exception("Throw exception explicitly!");
        }
    }
}

示例 2

// A.java
class A {
    @Transactional(rollbackFor = Exception.class)
    public void aMethod() {
        B b = new B();
        b.bMethod("111", true); // record of "111" has been rolled back and NOT created
        b.bMethod("222", true); // record of "222" has been rolled back and NOT created
        createRecordInDB("333"); // record of "333" has been rolled back and NOT created
        throw new Exception("Throw exception explicitly!");
    }

    // The annotation below is ignored
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void bMethod(String id, bool success) {
        createRecordInDB(id);
        if (!success) {
            throw new Exception("Throw exception explicitly!");
        }
    }
}

示例 3

// A.java
class A {
    @Transactional(rollbackFor = Exception.class)
    public void aMethod() {
        B b = new B();
        try {
            b.bMethod("111", false); // bMethod() has been rolled back, record of "111" has NOT been created
        } catch (Exception e) {
            // Do nothing, let it go
        }
        b.bMethod("222", true); // record of "222" has been created
    }
}

// B.java
class B {
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void bMethod(String id, bool success) {
        createRecordInDB(id);
        if (!success) {
            throw new Exception("Throw exception explicitly!");
        }
    }
}

示例 4

// A.java
class A {
    @Transactional(rollbackFor = Exception.class)
    public void aMethod() {
        B b = new B();
        b.bMethod("111", true); // record of "111" has been created
        b.bMethod("222", true); // record of "222" has been created
        createRecordInDB("333"); // record of "333" has been rolled back and NOT created
        throw new Exception("Throw exception explicitly!");
    }
}

// B.java
class B {
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void bMethod(String id, bool success) {
        createRecordInDB(id);
        if (!success) {
            throw new Exception("Throw exception explicitly!");
        }
    }
}

所有发布的示例都将打开一个新的事务上下文,而不管任何外部事务。因此 REQUIRES_NEW 将仅在其事务块内工作,并且仅在该范围内回滚更改。 您只需提供:

Class A {
    @Transactional(propagation=Propagation.REQUIRED)
    public void aMethod() {
        B b = new B();
        b.bMethod(); // success and committed
        aPrivateMethod(); // failure
    }

    private void aPrivateMethod() { //something }
}