views:

39

answers:

2

I just noted that my hibernate entities are automatically persisted to the database (or at least to cache) before I call any save() or update() method. To me this is a pretty strange default behavior but ok, as long as I can disable it, it´s fine.

The problem I have is I want to update my entity´s state (from 1 to 2) only if the entity in the database still has the state it had when I retrieved [1] (this is to eliminate concurrency issues when another server is updating this same object). For this reason I have created a custom NamedQuery that will only update the entity if state is 1. So here is some pseudo-code:

//Get the entity
Entity item = dao.getEntity(); 
item.getState(); //==1

//Update the entity
item.setState(2); //Here is the problem, this effectively changes the state of my entity braking my query that verifies that state is still == 1.

dao.customUpdate(item); //Returns 0 rows changes since state != 1.

So, how do I make sure the setters don´t change the state in cache/db?

Thanks, Kristofer

+1  A: 

Hibernate has built in support for what you are aiming to achieve - it supports optimistic locking using version ids or timestamps. If you try to save an object and the underlying data has changed, hibernate throws an exception. You can catch this exception and handle as necessary - ignore the update, retry or whatever makes sense.

See Optimistic Concurrency Control

EDIT: I'm not clear on how your update query works, but if you want to continue doing this by hand, you can evict your object from the session after retreiving it. This gives you a snapshot of the object as it was at retrieval time that you can modify independent from the db/cache. You can pass it into your custom update query as one side of the comparison, the other side being the persisted value. When the query selects/updates the entity, it will be re-read from the database, not from your evicted object. Your update query can then compare this with your evicted/modified value (passed as a parameter) to see if the update should be done or not.

See Session.evict()

mdma
A: 

You should set the flush mode of your session. That way the session entities will only be persisted after executing session#flush();

If you want the session cache or db to be updated, do something like this:

Bean bean = session.get(Bean.class, bean.getId());
session.setFlushMode(FlushMode.COMMIT);
// Make some changes to bean object.
Bean bean2 = session.get(Bean.class, bean.getId());
Assert.assertFalse(bean.equals(bean1)); // Assuming equals and hashcode are implemented
Kartik