-->
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.  [ 4 posts ] 
Author Message
 Post subject: How to rollback database operations that have been flushed?
PostPosted: Sun Aug 29, 2004 11:37 pm 
Newbie

Joined: Fri May 07, 2004 2:35 pm
Posts: 4
Hi,

I'm going to embeed a workflow engine (Jbpm2) into my application. The target platform for running my application is Spring framework. JBpm2's is using Hibernate as its persistence layer.

Before I go all the way embeeding Jbpm2 into my application, I conduct several small experiments. I'm concerned about transaction management. Here's one of the scenario that I tried:

My application has a service object, named Kwik. When Kwik::sayHi() is invoked, it:

[1] Perform db updates (on its own)
[2] Tell a process instance to proceed to next state (by calling Jbpm's ExecutionService::endState(..))
[3] Invoke another service object in my application (Kwak).

All those operation should be performed in a single transaction. That means: if step #3 fails, the process instance (whose state has been updated on step #2) should be automatically rolled back to its previous state.

In this experiment, I haven't use JBpm2. I used my own code, KwekImpl2, that behaves like Jbpm2 (in term of persistence operation). I mean, just like Jbpm2, KwekImpl2 builds the hibernate Configuration, and SessionFactory on its own. It also obtains Hibernate Session directly by calling SessionFactory. Normally, application that is intended to run on Spring, should open hibernate Session by calling Spring's SessionFactoryUtilL::openSession(...), in order to play nicely with Spring's transaction management. KwekImpl2 also starts a hibernate transaction on its own, by calling session.beginTransaction(), and performs commit on that transaction at the end of sayHo().

Important sources related to my experiment are: Main11.java, KwekImpl2, appctx13.xml, and hibernate.properties ( http://www.geocities.com/don_raka/latih ... ernate.zip ). The scenario described above failed. I've tried all configurations I can think of (related to distributed transaction management) both on Spring side (appctx13.xml) and Hibernate side (hibernate.properties). I'm using Jotm 1.5.3 as distributed transaction manager. Jotm's Current is bound to JNDI as "java:comp/UserTransaction" (such that Hibernate's JTATransaction can lookup that object from JNDI, @see JTATransaction::beginTransaction). I've configured both the spring & hibernate to use JTA transaction.

After several rounds of debugging, I found out that by the time JTATransaction::commit() is invoked -- see KwekImpl2.java, line 41 -- session.flush() is called. And apparently that transaction rollback that results from failure on step #3 didn't affect that modification.

I don't understand, it seems like hibernate's transaction is not aware that it takes part in a transaction that was started by other part of the application (Spring).

Please let me know what I've missed / done wrong. Perhaps any missing / wrong configuration?

Best regards & TIA,
Cokorda Raka ( http://www.jroller.com/page/donraka )
--------
Hibernate version: 2.1.6

Mapping documents:

Code between sessionFactory.openSession() and session.close():

Full stack trace of any exception that occurs:

Name and version of the database you are using: hsqldb 1.7.2

Debug level Hibernate log excerpt:


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 9:30 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
As long as you execute all those operations within a Spring-managed transaction, you should see a proper rollback in the case of failure. Are you sure that a single transaction spans all your operations?

Note that you don't need to do transaction management both in Spring and Hibernate: It's perfectly sufficient to just demarcate Spring transactions, with JtaTransactionManager as backend strategy. JtaTransactionManager should in turn be wired with JotmFactoryBean, and the Hibernate SessionFactory should use an XAPool DataSource.

The above is all you need: Hibernate should then seamlessly participate in JTA transactions, without any further setup necessary. In particular, you don't need to bind the JOTM UserTransaction to JNDI, a Hibernate doesn't need the UserTransaction at all in that case. Effectively, you don't even need a JNDI environment in that scenario.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 10:23 am 
Newbie

Joined: Fri May 07, 2004 2:35 pm
Posts: 4
Hi Juergen,

Here's the result of my debugging:

Instance of UserTransaction that is bound in spring application context has the following identity:
---------------------
ut= Current (id=276)
eventListStack= ThreadLocal (id=284)
nb_bg_tx= 0
nb_cm_tx= 0
nb_rb_tx= 0
nb_to= 0
transactionTimeout= 60

[So, I guess spring is using that UserTransaction]

----
As the result of invocation of doBegin() on Spring's JTATransactionManager, an instance of JOTM's TransactionImpl is created with the following identity:

tx= TransactionImpl (id=311)
delistedXARes= null
enlistedXARes= Collections$SynchronizedRandomAccessList (id=314)
interpose= false
myCtx= InternalTransactionContext (id=318)
myXid= XidImpl (id=307)
bqual= byte[17] (id=322)
formatId= 47892
gtrid= byte[17] (id=323)
internalVersId= 1
propagateCtx= true
recoveryCoord= null
subcoord= null
timer= null
ucount= 0

----
Hibernate's JTATransaction has reference to UserTransaction obtained from JNDI lookup. The identity is:

ut= Current (id=364)
eventListStack= ThreadLocal (id=368)
nb_bg_tx= 0
nb_cm_tx= 0
nb_rb_tx= 0
nb_to= 0
transactionTimeout= 60

(I guess that fact that Spring and Hibernate has reference to different instance of UserTransaction is okay, right? -- As long as userTransaction.getTransaction() return reference to same instance of javax.transaction.Transaction)
----
Through debugging I can see that Hibernate's UserTransaction has reference to the same instance of TransactionImpl -- as of Spring's.

tx= TransactionImpl (id=311)
delistedXARes= null
enlistedXARes= Collections$SynchronizedRandomAccessList (id=314)
interpose= false
myCtx= InternalTransactionContext (id=318)
myXid= XidImpl (id=307)
bqual= byte[17] (id=322)
formatId= 47892
gtrid= byte[17] (id=323)
internalVersId= 1
propagateCtx= true
recoveryCoord= null
subcoord= null
timer= null
ucount= 0

And you can see that "ut.getStatus() == Status.STATUS_NO_TRANSACTION" on Hibernate's JTATransaction line 146 returns false.
Plus, the if block on JTATransaction line 53 (inside the commit() method) never executes. This, I guess, is a proof that Hibernate has correctly participated in JTA transaction initiated by Spring.
----

But I wonder why I'm still not getting the desired behavior even under JTA transaction.

Best regards,
Raka


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 10:02 pm 
Newbie

Joined: Fri May 07, 2004 2:35 pm
Posts: 4
Hi Juergen,

I think I know where I did wrong....
Kwek's Session is currently not using XAConnection. I think I should configure hibernate.cfg.xml such that Kwek's SessionFactory obtains connection from XAPooledDataSource. I haven't tried this approach, just thought about it this morning. Will let you know of the result soon.

Best regards,
Raka


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.