-->
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.  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Hibernate design question - session and JDBC connection mgmt
PostPosted: Thu Jan 04, 2007 4:20 pm 
Newbie

Joined: Mon Jul 24, 2006 1:35 pm
Posts: 10
Hi,

I'd like to find out how Hibernate deals with JDBC connections obtained from connection pool. My app runs in Sun app server. Connection pool points to Oracle db. I use CMT for transaction management.

When I need to get Hibernate session I call SessionFactory.getCurrentSession(). I understand that session is bound to JTA transaction.

What I don't understand is the underlaying management of db connections (obtained from the pool) by Hibernate session. When I call SessionFactory.getCurrentSession() does the session check out a db connection from the pool and use the same connection for the duration of the transaction? So all other calls to SessionFactory.getCurrentSession() performed within the same transaction end up using sessions bound to the same db connection?

Or is the session always the same (within one transaction), but connections are dynamically checked out from the pool?

I'd appreciate a verbose explanation of how this works. I need to call a dbms package in Oracle to set user login (some tables in the db are restricted to certain users only), and I'd like to find out when should I make that call. If all data coming from session is bound to single connection, that would make things easy.
Regards,

Bratek


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 5:13 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
Probably an incomplete explanation...

When using Hibernate with a connection pool, whenever a Session needs a JDBC Connection, it allocates it from the pool.

When the session is done, it's behavior depends upon ConnectionReleaseMode. For Hibernate 3.1, the default ConnectionReleaseMode is AFTER_TRANSACTION (was ON_CLOSE), meaning that a Session releases Connection back to pool at the transaction end (commit or rollback).

Since you should always use transaction, this means that between your transactions the Session does not 'have' any JDBC Connection - it is back to the pool.

When using a JTA datasource, you may configure ConnectionReleaseMode to AFTEER_STATEMENT, meaning that Session will release Connection after each statement ... but there are some caviats ... and I don't use JTA.


Note there is a method Session.isConected(). The Session interface documemntation is somewhat incorrect, because it will return 'true' when a Session has a JDBC Connection, OR IT HAS MEANS of getting one (such as allocating it from a pool - in essence, normally it always returns 'true'.

Now, the above is all nice, EXCEPT:
There is a bug (or 'feature' at least in 3.1): When you use lazy fetching, and lazy fetch occurs outside of your transaction, Session will allocate but NOT release JDBC Connection.
This is VERY UNPLEASANT, as your application may HOG multiple connections - and in fact, HANG when your pool connection limit is too low (our thick client with connection limit of 5 had that nasty habbit).

My current workaround is periodically calling ConnectionManager.afterTransaction() on sessions which are not in use and have a non-null ConnectionManager.connection (requires introspection = private member).

[And yes, I am trying to put together a simple case for bug report]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 6:12 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Quote:
outside of your transaction


You mean connections with auto-commit transactions and you probably didn't turn that on in the Hibernate configuration. So the Session will start a transaction (well, the JDBC connection provider will) when it needs a connection "outside of transaction demarcation boundaries".

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 6:41 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
Well, I do not want auto-commit.
I want all my transactions to be explicit and well-behaved, and there has been thousands of warning about dangers of tinkering with (Hibernate owned) JDBC Connection auto-commit mode.

The problem I describe is that despite using default settings, whenever lazy load happens "outside transaction boundaries", I end up with a JDBC Connection taken out of the pool, and sitting attached to my Session's ConnectionManager - unless I make another transaction on that Session (which often does not happen for a while).

And scanning all reference documentation, especially the ConnectionReleaseMode, I do not see any configuration setting such as "release connection after lazy load".
I hope you do not refer to:

hibernate.connection.autocommit
Enables autocommit for JDBC pooled connections (not recommended).
eg. true | false


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 6:46 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
Well, I do not want auto-commit.
I want all my transactions to be explicit and well-behaved, and there has been thousands of warning about dangers of tinkering with (Hibernate owned) JDBC Connection auto-commit mode.

The problem I describe is that despite using default settings, whenever lazy load happens "outside transaction boundaries", I end up with a JDBC Connection taken out of the pool, and sitting attached to my Session's ConnectionManager - unless I make another transaction on that Session (which often does not happen for a while).

And scanning all reference documentation, especially the ConnectionReleaseMode, I do not see any configuration setting such as "release connection after lazy load".
I hope you do not refer to:

hibernate.connection.autocommit
Enables autocommit for JDBC pooled connections (not recommended).
eg. true | false


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 7:20 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Of course I do. How else it is supposed to work? There is no magic other mode, you either get a connection with explicit transaction boundaries or you get one in auto-commit mode. Not enabling auto-commit and using the Session outside of transaction boundaries is not going to work. That is what the switch is for.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 7:22 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
And if you want to know why this is "not recommended", chapter 10 of the book in my signature explains that in much detail. The only real usecase for it I've found is in desktop applications that access a database server directly with Hibernate.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 8:14 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
Christian, thanks for your attention to this.
I am sorry but I am probably not explaining it correctly.

I am NOT using Session "outside transaction boundaries".

Hibernate is.

Hibernate is using Session "outside transaction boundaries", to perform lazy intialization - and that lazy intialization, performed by Hibernate outside MY transaction boundaries, leaves an UNRELEASED JDBC Connection.

My unit test is using a lot of "our" layer over Hibernate, so here goes a simple stranscription of my problem:

TestInst class has a set of TestData, lazily loaded (see mapping below).

Code:
       
        Session ses = getSession();
        Transaction tx = ses.getTransaction();
        tx.begin();
        TestInst inst = (TestInst)ses.load(TestInst.class, new Integer(1));
        tx.commit();
       
        // The set of TestData is NOT loaded yet, and JDBC Connection is released
        assertFalse(Hibernate.isInitialized(inst.getDataSet()));
        assertFalse(hasJDBCConnection(ses));
       
       
        // Now, intialize the set - indirectly to be sure
        Iterator<TestData> iter = inst_2.getDataSet().iterator();
        while (iter.hasNext()) {
            String value = iter.next().getValue();
        }
        assertTrue(Hibernate.isInitialized(inst.getDataSet()));

        // And the following test fails, as the session now HAS a JDBC Connection     
        assertFalse(hasJDBCConnection(ses));


The boolean hasJDBCConnection(Session) essentially returns (via introspection)
ses.getJDBCContext().getConnectionManager().connection != null;
as ses.isConnected() is not very usefull

The TestInst to TestData mapping is:
Code:
   
<set name="DataSet" inverse="true" order-by="Instance" cascade="save-update,delete,all-delete-orphan,evict" lazy="true"  >
      <key>
        <column name="InstrId" scale="11" precision="0" not-null="false" />
      </key>
      <one-to-many class="com.recordfusion.gen.util.db.hibernate.TestData" />
    </set>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 8:20 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
Oops, the line
Iterator<TestData> iter = inst_2.getDataSet().iterator();
should be
Iterator<TestData> iter = inst.getDataSet().iterator();


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 8:28 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
Going back to the original question:

"If all data coming from session is bound to single connection, that would make things easy. "

I am afraid that the answer depends also upon the connection pool, but with most pool implementations, individual calls to allocate a connection from a pool (caused by individual transactions) will each return different JDBC Connection (or, more precisely, Connection wrapper).

However, changing the ConnectionReleaseMode to ON_CLOSE would keep the same connection for the entire Session duration - which may be what the original poster wants.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 04, 2007 11:03 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Quote:
Hibernate is using Session "outside transaction boundaries", to perform lazy intialization - and that lazy intialization, performed by Hibernate outside MY transaction boundaries, leaves an UNRELEASED JDBC Connection.


?! What's the difference. You need to enable auto-commit mode for that or wrap your lazy initialization in a transaction block. If you do neither, it breaks. No surprise there.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 05, 2007 12:24 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
"! What's the difference. You need to enable auto-commit mode for that or wrap your lazy initialization in a transaction block".

Well, I dare to disagree.

"What's the difference?"
The difference is that it is not the application code causing JDBC Connection "leak". It is the Hibernate implementation, violating the contract defined by ConnectionreleaseMode. Hibernate re-allocated JDBC Connection without my knowledge, outside of my control.

1) "You need to enable auto-commit mode for ..."
I do not see any need to enable auto-commit mode (with all it's drawbacks), because I am not using it - and I am not commiting any data. In fact I am NOT accessing the database at all - Hibernate is. I am using Hibernate as advertised - to perform lazy loads.

2) "Wrap your lazy initialization in a transaction block"
You must be tired to suggest that. The whole purpose of lazy intialization is that it happens without my code knowing when and where it happens - this being the main 'appeal' of Hibernate. Are you serious to suggest that I must wrap every access to my Hibernate-persisted object using lazy intialization in a transaction (with my code not even having access to the session, hidden in the proxy)?

My simple explanation is as follows:
When Hibernate was using ConnectionReleaseMode.ON_CLOSE, it was perfectly fine to keep JDBC Connection 'unreleased' when performing a lazy load.
When Hibernate 3.1 was changed to default ConnectionReleaseMode.AFTER_TRANSACTION, nobody noticed that lazy loads re-allocate the connection (without releasing it) -- because in most cases, applications perform additional transactions after the lazy load, and such transactions then release the connection. The bug only applies when no other transaction takes place in that session, and session remains open for a substantial time period.

You seem to argue that 'lazy load' should be an exception to the ConnectionReleaseMode setting, but I claim this to be a serious bug. After all, Hibernate should surround "lazy load" with a (Hibernate) transaction.

The bug severity' is underscored by the fact that:
- there are NO interfaces allowing application to detect that session has an un-released connection
- there are NO interfaces allowing application to release such un-released connection
- even if there were such interface, how would application 'know' that a lazy load occured? (use an interceptor??)
- un-released connections can (and DO) hang-up application


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 05, 2007 1:25 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Quote:
I do not see any need to enable auto-commit mode (with all it's drawbacks), because I am not using it - and I am not commiting any data. In fact I am NOT accessing the database at all - Hibernate is. I am using Hibernate as advertised - to perform lazy loads.


Auto-commit mode has nothing to do with "committing data". Hibernate will release the connection, just as you wish, if you enable auto-commit mode. This is how this mode works. This is also the fourth and last time I'm repeating myself.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 05, 2007 3:50 pm 
Regular
Regular

Joined: Wed Dec 07, 2005 4:19 pm
Posts: 53
OK, again and again, I appreciate your patience with a dumbkopf like me.

You keep saying that to fix the problem, I should configure Hibernate to use autocommit.
Granted, that releases JDBC Conection - because it essentially changes ConnectionReleaseMode to AFTER_STATEMENT

However, using auto-commit mode is UNACCEPTABLE.
Using auto-commit=true can make sense in some specific scenario, but as you so eloquently describe in your book,
"Auto commit mode is almost always inappropriate in application"
(in my case application twice as big as Hibernate, using Hibernate both as a thick client and on JBoss side)

Hibernate InAction, 5.1.1, JDBC and JTA transactions clearly states:
"If a database connection is in auto commit mode, the database transaction will be commited immediatelly after each SQL statement,
and a new transaction will be started".
(I am sorry i did not buy your latest book yet - I did not plan on spending so much effort on Hibernate troubleshooting).

Unless there is yet another documentation surprize (and Hibernate autocommit is a different animal than JDBC autocommit),
setting hibernate.connection.autocommit to 'true' means that each statement will be commited separately - destroying my transaction integrity.
I have tons of fairly complex transactions, which need to either commit or be completely rolled back (as often happens on deadlocks).

What I CONSIDER A BUG is:
Hibernate "lazy load" does not honor ConnectionReleaseMode.AFTER_TRANSACTION, leaving (unexpectedly) allocated connections.

WHY I CONSIDER THIS A BUG is:

1) Lazy load is one of the fundamental Hibernate fetures

2) I can NOT find a piece of documentation that would tell me that
ConnectionReleaseMode.AFTER_TRANSACTION is NOT (meant to be) honored by a lazy load.

3) For a real application, which has to use autocommit = false, there is (currently) no workaround.
In fact, the application has no documented way of detecting the problem.
The application will simply 'hog' connections - behaving as ConnectionReleaseMode.ON_CLOSE.

4) From a logical standpoint, I see no reason WHY a lazy load could not 'restore' the session state.
At the "lazy load" begin, connection was released.
After the "lazy load", connection should be released as well.
(Granted, interceptor log shows that lazy load does NOT report using a transaction, but thare is clearly a lazy load start/end).

All that said, I was working on bugreport with (hopefully) a fix proposal.
I can not imagine that fixing this problem would have adverse effect.

Unfortunately, (in Denver, CO), we are "snowed in" again, and hence I am working from my laptop, which has no Hibernate source as of yet.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 05, 2007 6:54 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
mbrunecky wrote:
You keep saying that to fix the problem, I should configure Hibernate to use autocommit.
Granted, that releases JDBC Conection - because it essentially changes ConnectionReleaseMode to AFTER_STATEMENT


This is the mode you want, right? So why don't you do what I keep telling you and argue with me instead?

Quote:
However, using auto-commit mode is UNACCEPTABLE.


Make up your mind! Either you want it or not. You can't have anything else because there is nothing else.

Quote:
Using auto-commit=true can make sense in some specific scenario, but as you so eloquently describe in your book,
"Auto commit mode is almost always inappropriate in application"
(in my case application twice as big as Hibernate, using Hibernate both as a thick client and on JBoss side)


Reflect on the words "almost always".

Quote:
Hibernate InAction, 5.1.1, JDBC and JTA transactions clearly states:
"If a database connection is in auto commit mode, the database transaction will be commited immediatelly after each SQL statement,
and a new transaction will be started".


AT THE JDBC/SQL LEVEL.

This is the auto-commit behavior AT THE HIBERNATE LEVEL if you ENABLE it: The Session gets a connection, the connection is (put) in auto-commit mode, the Session executes a SQL statement (maybe to initialize a proxy or collection), the statement is committed immediately, the Session returns the connection to the pool.

THERE IS NO OTHER MODE if you don't want to wrap an EXPLICIT transaction block around your lazy loading (which is what most applications do, see "almost always").

Your magic "Hibernate should wrap a Hibernate transaction around this" is exactly what the auto-commit mode already does. YOU NEED TO ENABLE IT.

Quote:
(I am sorry i did not buy your latest book yet - I did not plan on spending so much effort on Hibernate troubleshooting).


You sure seem to expect that others put in a lot of effort to explain things to you. Nice. EOD from my side.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 16 posts ]  Go to page 1, 2  Next

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.