-->
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.  [ 10 posts ] 
Author Message
 Post subject: Multiple JTA transactions per session
PostPosted: Tue Apr 05, 2005 5:19 am 
Regular
Regular

Joined: Thu Nov 13, 2003 2:55 am
Posts: 71
Location: Sweden
Hibernate version: 3.0 rc 1

Name and version of the database you are using: MySQL 4 + InnoDB

Sorry if this is newbie, but I am unable to combine JTA and the session-per-request-with-multiple-transactions pattern.

Code:
    SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
    Session session = sessionFactory.openSession();

    UserTransaction ut1 = getUserTransaction();
    ut1.begin();
    // Read object from database, will associate Connection with Session
    ut1.commit();


    UserTransaction ut2 = getUserTransaction();
    ut2.begin();
    Transaction tx = session.beginTransaction(); // Join Hibernate Session to current UserTransaction
    // Read object from database, SEEMS TO REUSE CONNECTION and thus the Connection will not be a JTA resource
    // Update object
    session.update(project);
    session.flush();
    tx.commit(); // This line doesn't make any difference, since the transaction was not started by session.beginTransaction()
    ut2.rollback(); // This should rollback the update BUT DOESN'T, since the Connection is not managed by JTA
    session.close();



Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 05, 2005 1:36 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
You'll need to open a new session for that. and reattach you objects with LockMode.READ

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 05, 2005 1:37 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
BTW which appserver / JTA impl are you using?

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 05, 2005 2:05 pm 
Regular
Regular

Joined: Thu Nov 13, 2003 2:55 am
Posts: 71
Location: Sweden
emmanuel wrote:
You'll need to open a new session for that. and reattach you objects with LockMode.READ

Aha. So if I'm using the ThreadLocal pattern I'll have to flush, close and replace the session of the thread whenever I start a JTA transaction. Right?
emmanuel wrote:
BTW which appserver / JTA impl are you using?

Resin. (With org.hibernate.transaction.ResinTransactionManagerLookup of course)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 05, 2005 3:13 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Hum, I'm wrong.
Actually the JTA implementation should delist the underlying connection from the first tx and enlist it to the new one sincethe conenction is still used. I'm not a JTA spec expert, thus I'm not sure if it should/may work as I state and as you've coded
It has actually little link with hibernate.
Try do to the same code ith plain JDBC/Datasource usage (wo Hibernate) and check whether resin work as expected.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 05, 2005 3:32 pm 
Regular
Regular

Joined: Thu Nov 13, 2003 2:55 am
Posts: 71
Location: Sweden
emmanuel wrote:
Hum, I'm wrong.
Actually the JTA implementation should delist the underlying connection from the first tx and enlist it to the new one sincethe conenction is still used. I'm not a JTA spec expert, thus I'm not sure if it should/may work as I state and as you've coded
It has actually little link with hibernate.

As far as my investigations reached, the problem is that Hibernate does not close the connection (i.e. return it to the pool/DataSource) between the transactions. Since the connection is not (re)requested from the DataSource, it will not be associated with the current JTA transaction (by the TransactionManager managing the DataSource).

I'm no expert here either, but spontaneously it seems Hibernate does wrong in not returning the connection after the commit.

How is the TransactionManager/Transaction supposed to know somebody is already holding a resource (i.e. a connection) that should be enlisted?
Should the DataSource keep track of all connections provided to a Thread, and if that Thread starts a transaction enlist all those connections. (I cannot remember any such thing in the JTA specs).

emmanuel wrote:
Try do to the same code ith plain JDBC/Datasource usage (wo Hibernate) and check whether resin work as expected.


What do you mean?
Resin with JTA works fine without Hibernate.
Resin DB pool Hibernate works fine without JTA.
If I "manually" request a connection from the DB pool before starting a JTA transaction, it will not be enlisted. Resources are only enlisted with the transaction when returned from the DB pool.


Top
 Profile  
 
 Post subject: Not a JTA problem
PostPosted: Wed Apr 06, 2005 3:36 am 
Regular
Regular

Joined: Thu Nov 13, 2003 2:55 am
Posts: 71
Location: Sweden
I tried another JTA implementation - JOTM - and the result is the same. JOTM actually has support for what they call "late enrollment", which associates an already opened connection with a transaction at begin(). AFAIK this features is proprietary and not part of JTA. Also, it seems you have to do some additional implementing for this to work, so I haven't actually tried it.

Anyway, it seems we can rule out errors in Resins JTA implementation (at least on this regard...).
So this leaves two alternatives:
- Is flushing, closing and reopening a connection before every JTA transaction the correct way to go?
- Or is there something wrong with Hibernates handling of connections when using JTA...?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 06, 2005 4:26 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
mate wrote:
I'm no expert here either, but spontaneously it seems Hibernate does wrong in not returning the connection after the commit.

It does make perfect sense a non JTA environment.

Quote:
How is the TransactionManager/Transaction supposed to know somebody is already holding a resource (i.e. a connection) that should be enlisted?
Should the DataSource keep track of all connections provided to a Thread, and if that Thread starts a transaction enlist all those connections. (I cannot remember any such thing in the JTA specs).

I would say yes, the DB keep track of all connections provided to a thread and to return the *same* connection while requestion the same DS. While not mandatory, I don't know any app server not doing this.

What you can do is disconnect() and reconnect() the session to get a new connection from the DS

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 06, 2005 4:55 am 
Regular
Regular

Joined: Thu Nov 13, 2003 2:55 am
Posts: 71
Location: Sweden
mate wrote:
I'm no expert here either, but spontaneously it seems Hibernate does wrong in not returning the connection after the commit.

emmanuel wrote:
It does make perfect sense a non JTA environment.

Yes. But this is a JTA environment. Maybe this should be managed differently there?

mate wrote:
How is the TransactionManager/Transaction supposed to know somebody is already holding a resource (i.e. a connection) that should be enlisted?
Should the DataSource keep track of all connections provided to a Thread, and if that Thread starts a transaction enlist all those connections. (I cannot remember any such thing in the JTA specs).

emmanuel wrote:
I would say yes, the DB keep track of all connections provided to a thread and to return the *same* connection while requestion the same DS. While not mandatory, I don't know any app server not doing this.

Firstly, this is assuming the connection has been "closed" or "returned to the pool". If you open two connections at once (for example by mixing Hibernate and pure JDBC) you get - and should of course get - two different connections.

Secondly, Resin (2.1.x) guarantees to return the same connection only if within a (JTA) transaction. If no (JTA) transaction is started, the thread will get the first available connection from the pool just as when the thread requests a connection the first time.

I would actually expect this to be common behaviour. AFAIK most application servers also provide a thread pool, so that threads are shared among consecutive requests. If the connections in the connection pool were always (whether in a transaction or not) associated with a (pooled) thread - so that the threads get the same connection from the connection pool every time, over multiple requests - the connection pool would be rather useless.

emmanuel wrote:
What you can do is disconnect() and reconnect() the session to get a new connection from the DS

Yes that works.

Though this cannot be such a unique scenario, can it. How is everybody else solving this???


Top
 Profile  
 
 Post subject: Patch!
PostPosted: Thu Apr 07, 2005 8:52 am 
Regular
Regular

Joined: Thu Nov 13, 2003 2:55 am
Posts: 71
Location: Sweden
I have now tried two alternative solutions for this. Firstly, it is possible to create an Interceptor, which disconnects and reconnects the session after transaction begin.

Code:
  public void afterTransactionBegin(Transaction tx) {
    Session session = HibernateSession.currentSession();
    session.disconnect();
    session.reconnect();
  }

I also tried patching JTATransaction.java and recompiling Hibernate. The fix is to add disconnect/reconnect after the UserTransaction is started (that is, after line 72), to make sure the connection that will be used is enlisted with the JTA transaction.:
Code:
98:     jdbcContext.disconnect();
99:     jdbcContext.reconnect();
100:
101:    begun = true;
...

I don't know enough about Hibernates internals to determine whether this might cause any other problems, or to write a testcase, but I would be glad if somebody could verify this and include it in the next release.

Though I must admit I am still in doubt here; is there really no simpler solution that everybody else is using?


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