-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: Session flushes even when transaction is marked for rollback
PostPosted: Sun Mar 02, 2008 4:05 am 
Newbie

Joined: Sun Mar 02, 2008 2:05 am
Posts: 6
Hi all,

Scenario:
Our app: A web application

Deployment env: 2-tier architecture where web-tier and business-tier run in the same JVM.

Transaction Management Strategy: JTA-enabled, session-per-request strategy. We use a Transaction Filter (something like hibernate filter and uses Spring's TransactionTemplate internally) that starts a new transaction and commits/rollback on the way out. Business Service layer (POJO, non-EJB) is decorated with Spring's AOP Transaction Interceptors with attribute Propagation_Required. So, our business services always join an existing transaction started by transaction filter.

Hibernate version : 3.2.1 sp4

Name and version of the database you are using: Oracle 10.2g

Hibernate Settings: Default settings (so session flushmode gets automatically set to AUTO and connection_release_mode to after_statement (since JTA) by hibernate)

Steps Performed

    1. I submit a form from one of the web pages.

    2. In the business layer of my application, some of the persistent domain objects are modified and after some processing but before issuing a hibernate save/update on those domain objects, some business rule is violated and an exception gets thrown.

    3. On the way out of the business layer, Spring's Transaction Interceptor marks the JTA transaction for rollbackOnly (by calling setRollbackOnly on JTA TM).

    4. Now in the action we have to redisplay the form along with the BusinessException Message, and since the form is complex, to show the original form, we have to perform a few db queries. Since we are using HQL, and session flush mode is auto, it flushes the session, which persists the domain object's dirty data to database. Note that transaction has not been committed yet (since we do that in Transaction Filter).

    5. I opened a separate sql client window and did a query on the database. Found that values that were flushed in the above step are visible in the database! Since the transaction isolation level of our db is read-committed, we should not be seeing here the above flushed dirty data as transaction has not been committed yet.

    6. After the necessary queries to display the form are performed, control returns to my Transaction Filter where we do a rollback. ( Since we are using Spring's Transaction Template, it does it in a little round about way; instead of doing an explicit rollback (since JTA Transaction was marked for rollbackOnly), it issues a commit anyways, which, fails and throws an exception. Shouldn't really be a problem though).

    7. The original web page is rendered along with the exception message.

Problems/Questions

    1. As we saw in steps 4 and 5 above, flushing also committed the data. Is this expected?

    2. I don't think hibernate should have done any flushing at all when I issued the HQL query in step 4. Internally, it should do a check if transaction is marked for rollback and not do any flushing if it is. Instead, it checks if the existing transaction is in progress and if it is, goes ahead and auto flushes the data. The logic used to determine if transaction is in progress also looks a little questionable to me. Following is the code snippet from JTAHelper:

    Code:
    public static boolean isInProgress(int status) {
        return status==Status.STATUS_ACTIVE ||
        status==Status.STATUS_MARKED_ROLLBACK;
    }


    Why is STATUS_MARKED_ROLLBACK a candidate for flushing? Is it deliberate? There is another method isRollback in JTAHelper with following code:

    Code:
    public static boolean isRollback(int status) {
       return status==Status.STATUS_MARKED_ROLLBACK ||
                 status==Status.STATUS_ROLLING_BACK ||
                 status==Status.STATUS_ROLLEDBACK;
    }


    I believe hibernate should also call JTAHelper.isRollback() to determine if it transaction is marked for rollback and refrain from flushing accordingly. Is it a bug? Or am I missing something?


Possible solutions

1. I can write a new AOP interceptor that gets the current session bound to thread and calls session.clear() if current transaction is marked for rollback. I can plug it in just before the Spring's AOP transcaction interceptor (which is plugged in before any business service is invoked).

2. In the AbstractDAO (which provides helper methods to perform queries on db) of my application, I can add a method that does the same as above interceptor and hook it up with remaining methods in that class.

3. Other solutions? Please share your thoughts.

Thanks.


Top
 Profile  
 
 Post subject: Re: Session flushes even when transaction is marked for roll
PostPosted: Sun Mar 02, 2008 11:25 am 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
The flushing behaviour is alright and it is necessary for certain use cases. However, I don't understand why you see the values in db, in another thread. Read committed should make those values invisible to other transactions.

As for suggestions I would argue it is better to set a session's flush mode to never in case of a roll back so that you can still be able to benefit from the data that has been load in L1 cache. Stacking interceptors as a solution is fine but I still believe you should solve this by transaction isolation level and not any other extra code. To me the problem with stacking interceptors is that what if Spring changes x and it is not going to work with your modification.

Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 02, 2008 8:59 pm 
Newbie

Joined: Sun Mar 02, 2008 2:05 am
Posts: 6
Thanks for your reply, Farzad.

On further debugging, found that connections that were being used underneath had autocommit set to true for JTA transactions. We are using a c3p0 datasource (Hibernate recommended) that has been added to JBoss JNDI and retrieved using Spring. So when the session gets flushed while executing an HQL, it commits it as well, thanks to autocommit set to true. One thing I should mention is that the datasource is non-xa since c3p0 and xa don't go together. I tried setting hibernate.connection.autocommit to false, but this was ignored since the datasource was from jndi. When I switched to a non-JTA configuration (I can since I am using only 1 datasource - oracle), and configured c3p0 connection provider properties as part of hibernate properties, then I was getting connections that had autocommit set to false and everything went fine during flushing as well (no data was committed now).

One of the possible solutions that I gave above about doing a session.clear() was plain wrong. Instead, I should set the current session's flushmode to NEVER/MANUAL when transaction is marked for rollbackOnly. But again, as you rightly said, there should not be any need to add extra code. If I can get connections whose autocommit is set to false, things should be fine.

But the question is, Doesn't c3p0 and JTA go together?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 02, 2008 9:05 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
This is totally my understanding and I might be wrong but as far as I understand c3p0 is a local resource that does not sync with a JTA transaction manager and therefore the answer is no. You need to get connections from a datasource that syncs with the transaction manager in an environment.

However, autocommit=true is totally wrong in any transaction scope, even if it is a hibernate managed transaction and c3p0 should definitely work with hibernate managed transactions.



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 02, 2008 9:35 pm 
Newbie

Joined: Sun Mar 02, 2008 2:05 am
Posts: 6
Thanks again.

When I was using c3p0 in a non-jta env, hibernate internally sets autocommit to false on each connection retrieved from a C3P0ConnectionProvider class.

But I am not so sure that c3p0 can't be used in a JTA env. c3p0 also publishes an MBean that can be used to configure a jndi datasource for JBoss App server. Why would they do that if the connections that this jndi datasource would give back has autocommit set to true? I tried to access c3p0 site (http://www.mchange.com/projects/c3p0/) but looks like it is down.

If c3p0 doesn't work, then I can shift to dbcp as I know that it gives connections whose autocommit is false.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 02, 2008 9:38 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
vijay2002 wrote:
but looks like it is down.



Google cache it...



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 02, 2008 11:06 pm 
Newbie

Joined: Sun Mar 02, 2008 2:05 am
Posts: 6
farzad wrote:
Google cache it...
Farzad-


I had already done a google search but wasn't of much help. I searched c3p0 mailing list and didn't find anything about this issue. I went through c3p0 documentation on hibernate's site (http://www.hibernate.org/214.html) and found that it doesn't provide any configurable property to set autocommit to false. It has a autoCommitOnClose property but its purpose is something else.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.