Friday, January 09, 2009

Hibernate: What does update actually mean?

I work on a large enterprise application that uses hibernate for it's persistence.

I regularly in the code base find the equivalent of...
Person person = personDao.loadById(id);
person.setLastname("newlastname");
person.setFirstname("newFirstname");
personDao.update(person);
The update call in the above code snippet is unncessary and useless.

Even after being on the project for more than 2 years I still find developers not understanding the purpose of update and I think I understand why. The obvious thought process is, I've changed a stored object, I now need to call update to save the change; sounds reasonable enough? That however, is not the purpose of update.
This particular use of update belies a misunderstanding of the nature of hibernate, and that is that it is a "transparent" persistence framework. What that means is that persistence is made to be transparent to the developer. You should not have to worry about the persistence issues. You load objects from data store, you change the objects, and the changes are saved, without any explicit save instructions. Imagine for a minute, if you had to call update whenever you made a change the complexity upgrade would be significant as it would mean having to track all the objects you do in fact change.

So then, if update is not for that, then what is it for?

The update method could have been named "attachAndPersistChanges" - that is a more accurate name, but probably a little unwieldy. It could also be described by the sentence "update this object in the data store". In other words, update is designed for objects that are not currently persistent.

The update method makes objects that are not persistent, persistent and updates the persistent object with any changes present in the not persistent (detached) object. The object must not already be available in the level one (session bound) cache otherwise an exception will be thrown (for this situation, use merge).

It does nothing for objects that are already persistent. I do not know if there is a performance penalty with running update on an already persistent object, if there is, it's probably minimal. It does clutter up the code with needless lines however.

Then when should I use it?

My current project is a large enterprise system with java on the back end, .net on the front end and web services in between. The front end is fairly light and thus does not know about the data model. For that reason the front end does not operate directly on the data objects. If it did, there might be a case for using update. i.e. I've received an object from the front end with changes that were made by the user. and I need to persist those changes so I call update on the object. The pattern we follow however is the one outlined in the code snippet. Load an object from store, make changes to it based on data received from front end - changes are automatically persisted, no update call.

But there is one case that I've encountered where we do need to use update and it illustrates an important thing to remember about hibernate...

Consider the code... 
transactionController.startTransaction();
Person person personDao.loadPersonById(personId);
person.setLastName("newLastname");
person.setFirstName("newFirstname");
transactionController.endTransaction();

transactionController.startTransacton();
person.setLastName("secondLastname");
transactionController.endTransaction();
I know it's a silly piece of code and you wouldn't find it like this in reality, but it illustrates the case simply. It is setting up a case where there are two transactions and one transaction is interacting with an object which another transaction touched.

What will the value of person.getLastname on the database? Believe it or not, the value will be unaffected by the second setLastname operation. It will be "newLastname". Why, what's going on?

The thing to remember here is that as far as hibernate is concerned, from the perspective of the second transaction, that person object is transient. The session that it was connected to is now closed and any change that is made to it is made as if it's a normal pojo with no knowledge of the persistence store even though a new transaction has been started. That object does not know about the new transaction.

And that is where update comes in. An update needs to be called on the person object in the second transaction to persist the change to lastname. This as we explained earlier, will attach the object to the new session and apply any required updates. 
transactionController.startTransacton();
person.setLastName("secondLastname");
personDao.update(person);
transactionController.endTransaction();
On our project, that is the only legitimate context where update is appropriate and necessary.

5 comments:

Lincoln said...

This is not necessarily true. For instance, if you have disabled auto-commit, then you will manually need to call update, then flush the result to the database.

AhmedAdel said...

is "end transaction function" do commit ????????

mx said...

Yes, I'd admit, there's no explicit "session close". The end transaction does all that, flushes any pending changes and commits the transaction.

Auto commit is off.

Being an enterprise application we let spring handle the transactions.

JeffM said...

I know this might sound obvious and trivial , but the the essence of it all is that ,as long as the POJO is not associated with a Hibernate Session , then its existence is evanescent(as far as Hibernate is concerned).

Job said...

you assume in your code then that the underlaying persistence is hibernate instead of another one.
If you make the call to update alle dao implementation can handle it, if you don't make the call only the ones with persistence frameworks like hibernate will work.

so i still will always call the update method