How to change Hibernate´s auto persistance strategy
I just noticed that Hibernate entities are automatically persisted to the database (or at least to 开发者_运维问答cache) before I call any save()
or update()
methods. 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 that I want to update my entity's state (from a state "1" to state "2") only if the entity in the database still has the state it had when I retrieved it (state "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 it is in the expected state "1". 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 breaking my query that verifies
// that state is still == 1.
dao.customUpdate(item); //Returns 0 rows changes since state != 1.
How do I make sure the setters don't change the state in cache/db?
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()
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
精彩评论