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

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.

Related

Prevent hibernate from flushing on read only operations

I have a heavy operation, which is read only. This is all mapped by hibernate, in a spring boot application.
Hibernate spends 6seconds flushing my entities, when there is no mutation of any sort. This is simply a get operation.
I am trying to stop hibernate from spending that 6 second, flushing redundantly.
I put hibernate flush mode to MANUAL/NEVER. But it didn't make any difference.
The property is set correctly, but hibernate stats still show the flushing, count, and the time spent.
There are several ways to do it. You may try:
org.springframework.transaction.annotation.Transactional annotation set to read-only:
#Transactional(readOnly = true)
Which in case of Hibernate, it sets the JDBC transaction into a read-only mode and FlushMode.NEVER.
Here details: https://stackoverflow.com/a/1712328/5810648
Also, it is possible to disable dirty-check calling setReadOnly(true) on Hibernate query or call setHint("org.hibernate.readOnly", true) on JPA query. According to doc :
Hibernate will never dirty-check them or make changes persistent ( eg.
new Boolean(true) ), default to false
http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html#d0e1215
Another way is to use stateless session for that heavy operation. Here is details: https://stackoverflow.com/a/5497077/5810648

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

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.)

JPA transaction combination of readonly and read uncommitted

Using Spring transactions, JPA with Hibernate implementation.
I have marked a method as:
#Transactional(readOnly=true, isolation=Isolation.READ_UNCOMMITTED)
Does this combination of readOnly and read uncommitted valid? I am using this on a method who's native sql is a select statement for a report page. First, I am marking it as read uncommitted so that it does not get stuck waiting on the table which gets frequently updated, as user wants to generate report even during processing time (a warning is shown if this happens). Second, I am marking as readonly to tell JPA not to keep the entities in the persistent context.
Is this a correct understanding?
Since you need intermediate data during the processing time, READ_UNCOMMITTED isolation level makes sense.
ReadOnly transaction will make sure that all the sql statements in that particular transaction are Select statements and if it finds any Insert/Update sql statements, it will immediately throw an error.
I think ReadOnly is just an additional check to make sure that your are not updating any data during a particular transaction.

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.

hibernate's transaction read and subsequent update

I have situation in which I read a record from a database. And if everything is ok I'll modify few properties and commit transaction.
But in situations two threads do the same, they will update the same record.
How to make it in hibernate?
You can use optimistic locking: give entities a version and let it throw an exception and try again later if the version isn't the same because something else (other thread, other node in a cluster or even some independant sql script that bothers to update the version) changed the same entity.
Or you can use pessimistic locking: really lock the entities in the database.
See the Transactions and Concurrency chapter in the hibernate documentation for more details.

Categories