yasi
yasi

Reputation: 473

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?

Upvotes: 2

Views: 3707

Answers (2)

Ravi Kapoor
Ravi Kapoor

Reputation: 21

All posted examples will open up a new transaction context irrespective of any outer transactions. Hence REQUIRES_NEW will only work within its transactional block and rollback changes within this scope only. You just need to provide:

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

    private void aPrivateMethod() { //something }
}

Upvotes: 0

yasi
yasi

Reputation: 473

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

Upvotes: 2

Related Questions