grails nested transaction bean reset

726 Views Asked by At

I'm using grails 1.3.7 together with Oracle 11g and trying to manage inner transactions. I have a bean Person that is passed to a transactional (Propagation.REQUIRED) service method who makes some modification. Then it is passed to another transactional (propagation = Propagation.REQUIRES_NEW) method that makes some other modification and then throws an Exception. What I expected to see is the rollback of all the modification of the second service but still valid those of the first one. This is the situation:

//outer transaction
class MyService {

    def nestedService

    @Transactional(propagation = Propagation.REQUIRED)
    public void testRequiredWithError(Person person) {
        person.name = 'Mark'
        try {
            nestedService.testRequiresNewWithError(person)
        } catch (RuntimeException e) {
            println person.age //this prints 15
            println e
        }
    }
}//end MyService

//inner transaction
class NestedService{

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testRequiresNewWithError(Person person) {
        person.age = 15 //expected after Exception will be discarded
        throw new RuntimeException("Rollback this transaction!")
    }
}

then I run grails console and check on the DB after it ends. ...

 def p = Person.get(671)
    def myService = ctx.myService 

    println p.name //'John'...from DB
    println p.age  //25...from DB

    myService .testRequiredWithError(p)

    println p.name // 'Mark'....correct
    println p.age  //  15....UNEXPECTED..
    //same result checking on the DB after console ends and transaction flushes

I tried to use Propagation.NESTED after activating it in the bootstrap by transactionManager.setNestedTransactionAllowed(true)and use savepoints like in this post grails transaction set savepoint but still got same result.

What am I missing????

Thank you in advance.

2

There are 2 best solutions below

1
On

I'd test for p.isAttached() as transaction rollback detaches the domain object from the Hibernate session. Also in the test I'd reload the domain object from database - effectively p = Person.get(671) again to reload data from database.

I think the reason the age property is set to 15 after the test is that after the exception the domain object and the database are out of sync (and the domain object is detached).

For more see: https://weblogs.java.net/blog/blog/davidvc/archive2007/04/jpa_and_rollbac.html

2
On

I'm a little late to the party but in case you haven't found your answer I think I know why you're having issues with transactions.

I looked at your link to the discussion about your issues with savepoints. According to that discussion you are using MySQL as your datasource. MySQL does not support transactions by default and in order to make it do so, you need to create your tables in a special way. I have provided a link below that explains how you should create your tables in MySQL when you want to use transactions:

http://www.tutorialspoint.com/mysql/mysql-transactions.htm

EDIT: This article suggests setting the type of your table to InnoDB in order to support transactions. Here is an example of what that looks like:

mysql> create table tcount_tbl
    -> (
    -> tutorial_author varchar(40) NOT NULL,
    -> tutorial_count  INT
    -> ) TYPE=InnoDB;

It might be worth noting that this is not the only type that supports transaction but is the most common. MySQL 5.5 and greater should create tables as type InnoDB automatically.

Hope this helps!