Saturday, January 05, 2008

Yet again..Hibernate get, load...and delete using references from Java Persistence With Hibernate

It seems that talks, questions and mini arguments about Hibernate and its use will never end among J2EE developers. I have noticed though that there are some points that often come up, yet again and again and again!

I am just going to add some comments on stuff that are already there in the documentation - so no rocket science especially for the experienced developers - you know most of that!

1. Session.get , Session.load

A well known question in interviews ;) is the following:

Can you please tell me the difference of Session.get and Session.load

Session.get no matter what will always do a hit on the database, and will try to bring into life a persistent instance of the ..whatever you are looking for!If not then it returns null! Nice and simple.

A common error seen on many developers - I do it as well sometimes is that - we always assume that this object exists and we rarely check for null. It is one of the most common causes of NullPointerExceptions in Hibernate use - at least from what I have seen doing code reviews!

On the other hand some will argue 'dude...usually obtaining an object reference using a surrogate key or primary key identifier , we are pretty much sure that it is there'.That's true Hibernate's Documentation states 'use get to check if something exists' (in other words either you want just to check if it is there, or you are 100% it is there).

In reality being lazy some times and not performing the check - your code fails because either the object is not there..and we have not use the null check.When it fails it fails really bad.Especially if this object reference you have just created to get the return from get is.....going around your code from method to method...you have a ticking bomb..of tricky null that is ready to explode (along with you and your application) when you try to operate on it!

//ok I assume that I got the car...but..
Car aCar = Session.get(Car.class,"papocar");
//now our reference is going all around
CarInsuranceService.addInsuranceToMyCar(aCar)
;

On the other hand Session.load will try to find the object's (instance) in the Session if it already initialized and live! In other words if the instance is somewhere in memory it will return this and will not hit the database. If it is not there you will have an ObjectNotFoundException. The tricky point here is the following, as mentioned both on Hibernat's documentation and in Page 405 of Java Persistence With Hibernate - you may have as return a proxy of the object - a fake object it looks like the one you want for sure but actually it is not going to work! So you invoke load and you have the proxy object as a result..and later on since it's a proxy and is not actually attached to persisted data - you will try to invoke something on it or get something for it..and you will end up with ObjectNotFoundException.

It is very clear that both of them serve different needs, and will require from the developer a different approach on identifying the error! My preference would be to code defensively on these issues. Either check for null or try to deal with the exceptions of the load method.

2. Session.delete

It is very often junior developers that write Hibernate related code for the first time - to assume that Session.delete - deletes (at this very moment the method is invoked) the object from the database! Of course this is so wrong. The actual notion of delete is to make a persisted object -> transient! So that means, in a unit of work let's say a method that you use Hibernate (you have context) you may invoke delete on an object..this object will be marked as deleted by Hibernate BUT the actual deletion in the database is when the Session will close and Hibernate will flush and commit all the changes to the database. A very nice diagram that illustrates this change of state is in page 406 of Java Persistence With Hibernate (at the buttom).

Another one that often causes confusion and questions (it is quite fun because we were actually having this very same discussion back @ work yesterday) is the following - why do I have to load object's (using get or load) in order to delete them.

Funny the answer is written on page 407 of the book I just had a look,it is because you may have interceptors that have to run on the object - these interceptors can operate on loaded objects.

From the above is clear why if we try to create a transient object set some properties (keys) and then pass this object to Session.delete , it will report errors and fail.The hack wont work.

A safe solution is load it or load a proxy and then delete it. Don't worry Hibernate is smart enough to optimize the actuall SQL code that is going to be flushed on the RDBMS!!!!

No comments:

Post a Comment