springtransactional

Spring outer transaction failure roll back inner transaction


I have the following code using Spring @Transactional annotation.

//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 }
}

The behavior I expect of A.aMethod() is:

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

How can I set the @Transactional propagation parameters to achieve this?


Solution

  • Here's the conclusion.

    Example 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!");
            }
        }
    }
    

    Example 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!");
            }
        }
    }
    

    Example 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!");
            }
        }
    }
    

    Example 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!");
            }
        }
    }