Why session.refresh(Object, LockMode.UPGRADE) is deprecated in hibernate? - java

My Requirement:
I am using Quartz cron for triggering purpose, Many triggers are running on same row but base on different column. So when trigger need to update its related column. trigger first refresh(Session.refresh(object)) the object belong to it(object is selected at starting of trigger) from database and then take an UPGRADE LOCK at row level. if it is success on getting lock then is update column and use session.update(object) to update in DB. and release the lock.
What is the alternative of session.refresh(Object, LockMode.UPGRADE) and efficient way to avoid dirty update using hibernate ?
Why it is deprecated in hibernate ?

What is the alternative of session.refresh(Object, LockMode.UPGRADE) and efficient way to avoid dirty update using hibernate ?
Right there in the documentation:
Deprecated. LockMode parameter should be replaced with LockOptions
E.g., use refresh(Object,LockOptions).
It doesn't say why, but it's clear about what to do instead. (And there is a LockOptions.UPDATE.)

Related

Replace single entity in query cache from JPA/Hibernate/EclipseLink?

We need to cache the results of a query; the query returns the whole table of a database. The problem is that the database is changed externally by other application; the Java application making the query is notified with the exact primary key of the row changed.
Is it possible to replace only the changed element from the query cache, not the whole list?
Is this the 1st level cache (from EntityManager) 2nd level Cache (from EntityManagerFactory) or a different cache?
If it is possible can this be done from JPA?
entityManager.refersh(entity);
or is this query cache the 2nd level JPA cache:
entityManagerFactory.getCache().evict(cls, primaryKey);
or only possible through Hibernate/EclipseLink API?
If is not possible, in order to achieve this, would calling entityManager.find() on all elements do it?
I haven't find anything useful neither in Hibernate documentation nor in EclipseLink documentation. Hibernate supports regions and refreshing only regions, but we need entity-level refresh granularity.
Later edit to clarify my findings.
Following the link posted by #Chris in the comment I have found out that what I wanted is actually supported by EclipseLink but only for Oracle Database (there is possible to implement own handler for other vendors; but the call from database is not standardized and differs from vendor to vendor). I have not found if Hibernate supports this or not.
Anyhow the query cache from EclipseLink had some very poor performance compared with Spring Cache (based on CocurrentMap) or with custom based cache so will remain with Spring Cache or Custom Cache over Spring Jdbc.
EntityManager.refresh() is what you want - it refreshes the entity from what is in the database. This should also update the entity in the shared cache if you are not in a transaction, otherwise you may need to use the entityManagerFactory.getCache().evict(cls, primaryKey); as well to clear the second level shared cache so it can be read into it as well later on.

what is the purpose of LockMode OPTIMISTIC?

As per How to do optimistic locking in hibernate, we need to enable the optimistic
locking with version element or version annotation in hibernate. I am clear till here.
I am not sure what is the purpose of Lock Mode Optimistic ?
In what kind of scenario, developer should use it ?
to understand why you would want optimistic locking, you first need to understand what no locking and pessimistic locking mean. I'm no hibernate expert, so I'll just tell it to you without a focus on hibernate.
When 2 process/users update the same object then the one who updates it last will win. So you need to find a way to prevent this. One way to do this is pessimistic locking. Here, you will put a lock on the object at the moment you load it from database "select for update". Until your transaction is commited or rolled back, nobody else can "select for update" this object. now the problem is: When you load an entity via hibernate, you nowhere specify if you want to load it for read-only purpose or if you want to modify this object.
So here comes optimistic locking. This concept assumes optimistically that everything will go ok in most cases. When 2 processes/users update the same object, the second one will not win, but get an exception on commit.

SQL Server exclusive row lock (XLOCK ROWLOCK) using Spring Transactions using Hibernate

I am attempting to do a select on a row and update the value. While I do this I need exclusive access to the row. In other words, no other process (inside or outside the VM), should be able to read the row until after I update the row. The current value should not be "selectable". I have tried the following transaction annotation.
#Transactional(isolation = Isolation.SERIALIZABLE, readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class, timeout=960)
This definitely works within the Spring context, but while putting a sleep statement in the middle of the transaction, I'm still able to select the current row value using a database tool.
Is there a way to get a XLOCK/ROWLOCK (whichever is the appropriate) using Spring/Hibernate?
Versions:
Spring: 3.0.5.RELEASE
Hibernate: 3.6.3.Final
JTDS: 1.2.4
If I can't use Spring/Hibernate, a link to a JTDS example would be much appreciated.
Thank you.
SERIALIZABLE isolation level allows other transactions to read data, but not to modify. So you need to explicitly SELECT ... FOR UPDATE (in Hibernate: Query#setLockMode(LockMode.UPGRADE)).
Use explicit locking with the Hibernate. There is more information here.
However, I think you have to think once more time - do you really need the pessimistic lock? In most cases optimistic lock works better, and hibernate supports versioning very well.

Hibernate Dirty Object usage

I have a Hibernate Entity in my code. i would fetch that and based on the value of one of the properties ,say "isProcessed" , go on and :
change value of "isProcessed" to "Yes" (the property that i checked)
add some task to a DelayedExecutor.
in my performance test, i have found that if i hammer the function,a classic dirty read scenario happens and i add too many tasks to the Executor that all of them would be executed. i can't use checking the equality of the objects in the Queue based on anything , i mean java would just execute all of them which are added.
how can i use hibernate's dirty object stuff to be able to check "isProcessed" before adding the task to executor? would it work?
hope that i have been expressive enough.
If you can do all of your queries to dispatch your tasks using the same Session, you can probably patch something together. The caveat is that you have to understand how hibernate's caching mechanisms (yes, that's plural) work. The first-level cache that is associated with the Session is going to be the key here. Also, it's important to know that executing a query and hydrating objects will not look into and return objects from the first-level cache...the right hand is not talking to the left hand.
So, to accomplish what you're trying to do (assuming you can keep using the same Session...if you can't do this, then I think you're out of luck) you can do the following:
execute your query
for each returned object, re-load it with Session's get method
check the isProcessed flag and dispatch if need-be
By calling get, you'll be sure to get the object from the first-level cache...where all the dirty objects pending flush are held.
For background, this is an extremely well-written and helpful document about hibernate caching.

How to increase a version field on save in Hibernate regardless if dirty or not?

I'm using Hibernate with a version column to implement optimistic concurrency control.
The question: Is it possible to increment the version number of an entity every time I save it to database, regardless if it was changed or not?
As long as some field is changed in the entity, the version number gets increased. But, if no field changed in the entity, the version number of the entity stays unchanged.
The reason behind this question is that I've got a logical master-detail relationship between two tables and I'd like to increase the version number in the master table whenever something changes in details, even if master data didn't change. This master-detail relationship is not mapped in Hibernate. I just always save them together in a single transaction.
You can use Hibernate interceptors to update the version number of the master record when you identify that a detail has changed.
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/events.html
One limitation is that this solution is specific to Hibernate. JPA also allows event-driven logic using annotations (e.g. PostPersist, PostUpdate, etc...) but these methods don't give you access to the underlying session (and, more importantly, the documentation cautions you from using these methods to modify session data). I've typically used interceptors to perform auditing, but they could easily be extended to update a version number when a record is altered.
You can call lock() (or use other methods that take LockMode) with LockMode.OPTIMISTIC_FORCE_INCREMENT.

Categories