-->
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.  [ 39 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Extending the Hibernate Session to provide isTransactional()
PostPosted: Thu Jul 29, 2004 11:31 am 
Newbie

Joined: Thu Jul 29, 2004 10:54 am
Posts: 2
Location: Toronto, CANADA
I would like the ability to detect if a transaction is in progress or not so I can conditionally commit(), i.e. if there was already a transaction in progress then let the calling business method commit otherwise commit within the current busines method. If we were using a higher level (JTA) transactional context this wouldn't be necessary but unfortunately we're not.

The ideal would be to have a method isTransactional() on the Session that would check if there is an embedded transaction and it's neither committed nor rolled back. The SessionImpl class only has a private isCurrentTransaction but it doesn't know if it's been committed or rolled back.

Currently I'm using the ThreadLocal pattern to embed both the Session and Transaction and get a transaction through this new object so I can implement isTransactional() there but it would be cleaner if the Session provided that itself.

I tried searching the docs and Google but could find what I wanted -- sorry if this is repeat of something I missed.

Essentially I'm using the ThreadLocal pattern (with a wrapper class called DataAccessSession) in a web application and need to pass control between different business methods that would want to participate in (and not yet commit) an existing transaction if one is available, but need to create/commit their own transaction if one is not available. The isTransactional() would also help at the end of the service thread to rollback or commit any existing transaction.

Here is how I'm using the DataAccessSession which has an embedded ThreadLocal to track any existing transaction myself, but it depends on using DataAccessSession.beginTransaction so that it can track the transaction. It does what I want be please let me know if anyone knows of a better way.

if (das == null) das = DataAccessSession.getInstance();
try {
boolean myCommit = !das.isTransactional();
Transaction tx = das.beginTransaction();

Session hs = das.getSession();
ApplicationData appData = (ApplicationData) hs.load(ApplicationData.class,appId);
appData.setApplicationStatusCode(appContainer.getApplicationStatus());

if (myCommit) das.commit();

} catch (HibernateException ex) {
Logger.error(ex);
das.rollback();
}

_________________
\|/- Keith Mashinter, WCNA & AKME Solutions


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 29, 2004 11:33 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Please, always use transactions, and manage them at the point where you handle the opening/closing of sessions. There is no such thing as a "nontransactional data access", you should always do explicit transaction handling. Therefore we will surely not provide such a method, as there is no such thing as a "nontransactional Session".


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 3:13 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
michael wrote:
Please, always use transactions, and manage them at the point where you handle the opening/closing of sessions. There is no such thing as a "nontransactional data access", you should always do explicit transaction handling. Therefore we will surely not provide such a method, as there is no such thing as a "nontransactional Session".


This seems to have become the Hibernate mantra lately: Christian dismisses non-transactional access too whenever he has the chance to. While I tend to agree in general, that doesn't mean that there is no valid use case for non-transactional access, in particular when reading.

If you demarcate a transaction, you'll always create a database transaction, even if all you will perform is read operations that are very likely to find their data in the second-level cache. This represents a significant overhead compared to pure non-transactional cache access.

Of course, the target database is an important factor here: Handling a transaction on MySQL is pretty lightweight, but handling a transaction on Oracle is not. So while I generally recommend transactional access too, doing non-transactional reads on Oracle is a valid tradeoff, IMO.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 3:14 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
There is no non-transactional database access. If you know how, show me how to access Oracle without opening a transaction.

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


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 3:23 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Juergen, this is just wrong. There is no "notransactional database access". What you are describing is autocommit, where a transaction is automatically committed at the end of each request to the database.

So your "no transactions" actually means "many transactions".

Hence, it is potentially slower to execute many SQL statements, since there is a new transaction for each.

I have verified this with the guys at Sybase, incidentally.

In addition, transactions in Oracle are almost always very lightweight, since Oracle does not use a locking model (unlike MySQL).


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 3:47 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
P.S. I just tested performance with and without autocommit on MySQL, Oracle, SQL Server and HSQLDB and found no difference in performance for the single-threaded case. Assuming read-committed isolation, this result would carry over to the case of concurrent access.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 4:45 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
gavin wrote:
Juergen, this is just wrong. There is no "notransactional database access". What you are describing is autocommit, where a transaction is automatically committed at the end of each request to the database.


Gavin, I know :-) You might have noticed that I explicitly stated that I agree in general. I also didn't talk about non-transactional database access, just about non-transactional Hibernate Session usage when you expect to almost always hit the cache. I completely agree that transactional demarcation for actual database operations makes sense.

The special case I outlined is: If you can assume that 99% of your read operations will hit the second-level cache, it is significantly less overhead to just the hit the cache and not touch the JDBC driver in the first place, not even for transaction handling. Consider, for example, applications that often fetch the same persistent objects via id.

Demarcating a JDBC transaction at least means fetching a JDBC Connection from the pool and invoking commit at the end of the operation. (If default auto-commit is "true", you also need to set auto-commit to "false" at begin.) As this is not necessary when you just hit the cache, it unnecessarily incurs resource management overhead.

With Oracle, it makes a strong difference whether the pool has default auto-commit set to "false": The overhead is significantly less then. Unfortunately, you cannot influence the pool definition in some scenarios: You'll have to live with explicitly invoking setAutoCommit(false) then, which does incur a significant overhead on Oracle.

At least that's what I was told by various long-time Oracle users; I also experienced it myself recently. Particularly for setAutoCommit(false), the difference between Oracle and MySQL is significant. And as I said, why go through JDBC resource handling in the first place - for single loads that almost always hit the second-level cache?

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 4:54 pm 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
P.S.: Again, I do advocate transactional access in general. The difference is that I'm not as dogmatic about this as you seem to be, and that I'm specifically talking about the Session level. So I'm not claiming that

Quote:
there is no such thing as a "nontransactional Session"


There is, else Hibernate wouldn't have separate openSession and beginTransaction calls. And if you mainly use it for second-level cache access, the Session doesn't even fetch a JDBC Connection.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 5:03 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
It is true that you could avoid fetching a connection from the pool. However, assuming you have a decent connection pool, and that the pool as autocommit false, this should not be a significant overhead.

So basically this comes down to simply configuring your connection pool correctly.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 31, 2004 7:09 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
gavin wrote:
It is true that you could avoid fetching a connection from the pool. However, assuming you have a decent connection pool, and that the pool as autocommit false, this should not be a significant overhead.

So basically this comes down to simply configuring your connection pool correctly.


Well, there's a bit more to it: If you can hit the cache, you don't need to communicate with the target database at all. The target database can even be down - your read operations will still work! Consider that in the context of a public information system with a 99.99% read ratio.

With a transaction, you'll at least send a "commit" command to the target database, i.e. a synchronous network call. (And potentially also a "set autocommit=0" call on transaction begin.) You can avoid such calls if you just hit your local second-level cache - by not demarcating a transaction.

So leaving dogmatics aside, I do consider it a valid tradeoff to not demarcate required transactions for read operations that almost always just hit the cache. Of course, if a scenario is not so cache-heavy and/or requires strict isolation for reading, use read transactions by any means.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 02, 2004 9:44 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
It is trivial, decorate JDBC connection and make it "lazy".


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 04, 2004 6:42 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Actually, as long as you are using JTA, or a JDBC driver which already implements this optimization, there is still no difference.

It is the responsibility of JTA to optimize away unnecessary resource-level transactions, not of the application.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 13, 2005 3:54 am 
Beginner
Beginner

Joined: Wed Oct 19, 2005 4:11 am
Posts: 48
I just investigated the effect of non transactional read via a JDO 2 implementation to see if there is much of a performance difference in the non transactional read feature. The results are shown below and are quite amazing. If Hibernate supported non transactional reads I suppose there would be a similar performance gain but I don't know if this is possible or planned. There seems to be a lot of resistance to this feature in the Hibernate camp for some reason.

Results:

Reading a large, very complex object graph with many direct and indirect bidirectional references:

Object graph fetched within the context of a transaction:
1st Run - 3766 ms - fetched from database.
2nd Run - 3828 ms - fetched from cache but the overhead of transactional read is great.

Object graph fetched using a non transactional read:
1st Run - 3766 ms - fetched from database.
2nd Run - < 1ms - fetched from cache <- Amazing! It's hard to argue against this sort of performance gain.

We like Hibernate as a product, in fact we've gone to the effort of implementing Hibernate support in our Javelin Object Modeler/Coder product via the automatic generation of Hibernate mapping files. However, most of our users develop highly sophisticated "real world" models like the one we used in the performance test above. It would be great if the Javelin users who choose to use Hibernate persistence could benefit from the same performance gain as those users who choose to use JDO 2 persistence with non transactional reads.

_________________
Chris Colman
http://stepaheadsoftware.com/products/j ... avelin.htm
Javelin: Lightweight, non intrusive, POJO, Java modeling & coding with automatic Hibernate and JDO meta data generation.
Don't forget to credit ;)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 13, 2005 4:30 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
that definitly doesn't look like a transactional performance gain, but more a different cache strategy ?!

And your description is waay to sparse to tell where you get the performance gain from.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 13, 2005 4:45 am 
Beginner
Beginner

Joined: Wed Oct 19, 2005 4:11 am
Posts: 48
The only thing I changed between the two test runs were:

1. Commented out the surrounding tx.begin()/tx.commit()

2. Set the flag that enables non transactional reads in the properties files.

I know it sounds unbelievable - I was shaking my head for quite a while. I was amazed that non transactional reads had such an amazing performance effect - and that it could be achieved with such minimal code changes but heck it works so I was happy.

I have since changed the test slightly: previously I was writing the data to the database then reading it from within the same run. The tests now start up with the data already in the database and the results don't change that much at all.

Reading a large, very complex object graph with many direct and indirect bidirectional references:

Object graph fetched within the context of a transaction:

1st Run - 4125 ms - fetched from database.
2nd Run - 3656 ms - fetched from cache but the overhead of transactional read is great.

Object graph fetched using a non transactional read:

1st Run - 4125 ms - fetched from database.
2nd Run - 15 ms FAST!! - fetched from cache <- Amazing!

I suppose I could try turning off all caching to remove any influence of caching.

_________________
Chris Colman
http://stepaheadsoftware.com/products/j ... avelin.htm
Javelin: Lightweight, non intrusive, POJO, Java modeling & coding with automatic Hibernate and JDO meta data generation.
Don't forget to credit ;)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 39 posts ]  Go to page 1, 2, 3  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.