Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: Transaction propagation and exception rollback

  1. #1
    Join Date
    Sep 2004
    Location
    France
    Posts
    44

    Default Transaction propagation and exception rollback

    Hi,

    Here is my problem:
    - I declare in my appCtx file serviceA with a method with transaction attribute "PROPAGATION_REQUIRED,-Exception"
    - I declare another service, serviceB with the same attributes.

    If I call serviceA directly, if I have an Exception, my transaction rollback, everything is ok.
    If I call serviceB, which call serviceA. I have an exception in serviceA, I trap it and manage it in serviceB. ServiceB does not throw an exception : my transaction rollback.

    This is not the behaviour I expect. As my toplevel service is serviceB, is thought that the attributes behing used are those of serviceB. It seems that, after serviceA call, the transactioninterceptor use setRollbackOnly to force transaction rollback.

    Is there any way to avoid this ? If not do you have any solution to solve my problem ?

    Thanx

    Seb

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    If you want more details I recommend you read the 'Transactions' chapter from Spring reference documentation. A quick explanation would be:

    Your transactions attributes for serviceA instruct Spring to do a rollback on every exception serviceA gives - this is exactly what happens.
    To solve the problema you should restrict the exceptions on which Spring does rollback.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3
    Join Date
    Jun 2005
    Posts
    15

    Default

    I have this kind of code:

    Code:
    // firstly check if the object exist
    try{
        object = dao.findByPrimaryKey(...);
        // no exception thrown, means object in database
        object.setXyz(...);
        dao.update(object);
    }
    catch(ObjectNotFoundException e){
        // if not exist
       object = new AbcObject();
       dao.insert(object);
    }
    
    // commit the transaction
    The above code is so normal and reasonable. But since the findByPrimaryKey throws exception, it will cause the whole transaction roll back. That's not what I want.

    I think it would be better to let the first caller who initiate the transaction to commit or rollback the transaction. Any other callees should not make the decision on behalf of the caller because they don't know whether the original caller can tolerate the exception or not.

    Unfortunately, in my opinion, this is not the behaviour of the current Spring implementation. Maybe I am wrong, please correct.

  4. #4
    Join Date
    Sep 2004
    Location
    France
    Posts
    44

    Default

    You are right

    I dig into Spring code and found that if you have a Service that rollback on an Exception, it forces rollback even if it is encapsulates in another service that catch the Exception and manage it.

    I think this is also the ejb behaviour. I would like to have a method like 'setRollbackOnly(false)' that my second level service can use to unset the rollbackonly flag when it manages the transaction but I don't know it this is something possible

    seb

  5. #5
    Join Date
    Jun 2005
    Posts
    15

    Default

    I just did a test and, fortunately, it is not the EJB behaviour. I have this code:

    Code:
    // this is a method in a stateless session ejb with transaction required
    public void methodA(...){
       // if exception occur, always throw RuntimeException
    }
    
    // another method in the same session ejb with transaction required
    public void methodB(...){
        try{
            methodA();
        }
        catch(Exception e){
           // exception situation can be recovered
           // do something else
        }
        // continue ...
    }
    After methodB returns, transaction get committed. The failure of methodA doesn't cause the whole transaction roll back.

    The test runs on weblogic 8.14 sp4.

    For the time being, I have to use programatic transaction control, like this:

    Code:
    PlatformTransactionManager transactionManager = getTransactionManager();
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setPropagationBehavior(this.getTransactionAttribute());
    	
    TransactionStatus status = transactionManager.getTransaction(def);
    try{
    
        // call other methods that use transaction
    
        if ( status.isNewTransaction() ) { // only the originator can commit or rollback
            transactionManager.commit(status);
        }
    }
    catch (Throwable t) {
        if ( status.isNewTransaction() ) {
            transactionManager.rollback(status);
        }
        throw t;
    }

  6. #6
    Join Date
    Aug 2004
    Location
    Linz, Austria
    Posts
    391

    Default

    That test with WebLogic's EJB behavior doesn't look valid to me. You're calling methodA on the implementation class from methodB, so you're circumventing the EJB proxy completely - and thus won't apply the specified transactional behavior.

    You'll get the exact same behavior if you have a Spring-managed DAO where you call methodA on the implementation class from methodB: you'll be circumventing the proxy there as well - and thus won't apply the specified transactional behavior.

    In general, don't use transactional proxies for every fine-granular DAO. It's usually sufficient to demarcate transactions at the service facade level.

    If you still go down to the DAO read method level, you could specify the commit rule "+RuntimeException" in the transaction attribute, which will not trigger a rollback on any RuntimeException that comes out of that read method (which would by default lead to a rollback-only state).

    Note that the current behavior is well-defined: it just doesn't match your expectation. If you intend to proceed even with a RuntimeException, simply specify a corresponding commit rule (whether for a specific exception such as ObjectRetrievalFailureException or for RuntimeException in general).

    Juergen

  7. #7
    Join Date
    Sep 2004
    Location
    France
    Posts
    44

    Default

    In my personal case, I don't put transactional behavior at DAO level.

    I have an interactive service that rollback on exception when I try to create a domain object. I also have a batch service. This second service call the first one for each object, catch the exception that it may throw and manage this exception. In this case, as my batch service know what to do with individual create exception, at this end of the transaction, I would like to commit my work.
    The actual behavior seems ok to me. I just want to know if it is possible to add a setRollbackOnly(false) that my second service can invoke to override the default behavior.

    Does this seem valid to you ?

    Thanx for the reply

    Seb

  8. #8
    Join Date
    Jun 2005
    Posts
    15

    Default

    Make sense. Thanks Juergen!

  9. #9
    Join Date
    Jun 2005
    Posts
    15

    Default

    Oops, give a second thought, it still looks not that perfect. Think about this:

    A project manager initiates a project, and he assigns the tasks to several team leaders. Then each team leader re-assigns the tasks to his developers... but suddenly a developer encounters a problem and he himself can not go on. He writes a report to his boss (throws an exception) and, by default, cancels the whole project!

    Although I can declare +Exception to let the transaction continue, I wonder if it is better to by default let the transaction originator to make the decision.

  10. #10
    Join Date
    Aug 2004
    Location
    Linz, Austria
    Posts
    391

    Default

    I would still argue that you shouldn't put a transactional proxy in front of your fine-grained bean if you don't want it to cause rollback-only status. Why not use a transactional proxy in front of your facade bean only? In that case, that facade would be in full control over the rollback decision.

    BTW, a DataAccessException thrown by a fine-grained DAO might actually corrupt the persistence context that's associated with the current transaction (for example, the Hibernate Session). It's not generally possible to simply ignore this and continue with the rest of the transaction.

    Another option would be to keep the fine-granular transactional proxies but use PROPAGATION_NESTED there. That would cause a rollback to the implicit savepoint at the beginning of that operation. However, that generally only works with DataSourceTransactionManager on JDBC 3.0.

    Regarding setRollbackOnly(false): Such a call would be inconsistent with typical transaction patterns, and couldn't be guaranteed to work in general. A rollback-only marker might also be set by the transaction coordinator itself, for example caused by a transaction timeout.

    Juergen

Similar Threads

  1. flushing in transaction
    By hiberman in forum Data
    Replies: 0
    Last Post: Sep 2nd, 2005, 09:42 AM
  2. Transaction propagation
    By mettus in forum Data
    Replies: 4
    Last Post: Aug 3rd, 2005, 11:06 PM
  3. Transaction propagation and Exception
    By borland2004 in forum Data
    Replies: 6
    Last Post: Jun 14th, 2005, 12:57 PM
  4. Transaction propagation failure
    By vas in forum Data
    Replies: 3
    Last Post: Oct 15th, 2004, 09:07 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •