JPA 1.0 and Hibernate 3.4 generating FOR UPDATE NOWAIT when locking
I am currently working on a Java EJB project being deployed to Weblogic 10.3.3. We are using JPA 1.0 with Hibernate 3.4 as the implementor. We are also using the Oracle10g Dialect.
The issue we are running in to involves the generation of SQL by hibernate when attempting to lock a row for update.
We execute a query:
Query q = entityManager.createNamedQuery("findMyObject");
MyHibernateObject myObject= (MyHibernateObject ) q.getSingleResult开发者_StackOverflow社区();
And then lock that object with:
entityManager.lock(myObject, LockModeType.WRITE);
This act of locking generates the query:
SELECT myObject FROM myTable FOR UPDATE NOWAIT
What I want it to generate is:
SELECT myObject FROM myTable FOR UPDATE
Enabling other threads to query for this object without throwing the exception: org.hibernate.exception.LockAcquisitionException and to just wait their turn or let the EJB transaction timeout.
So knowing all this, can I force Hibernate to generate the SQL without the NOWAIT keyword?
I know that using Hibernate 3.6 and JPA 2.0 will allow this using a pessimistic lock but due to Weblogic only supporting JPA 1.0 our hands are tied.
Ideally I want to avoid writing our own retry and/or timeout mechanism by handling the exception when all I need is to just augment the SQL that Hibernate is generating when the EntityManager creates the lock.
Ok, we are using a workaround until we update to Weblogic 10.3.4
Here it is in case someone else stumbles upon this:
SessionImpl session = (SessionImpl)entityManager.getDelegate();
session.lock(myObject, LockMode.UPGRADE);
This of course breaks from the JPA standard, in that we are exposing hibernates implementation and using the hibernate session.
But it will generate a
SELECT myObject FOR UPDATE
instead of
SELECT myObject FOR UPDATE NOWAIT
Hope this helps someone.
Use below code to skip a locked row. This is the alternate of
select * from student where student id = n for update nowait
findStudnt method throws error if row is already locked. If there is no error call updateStudent method to update student entity else log the error for audit.
@Override
public Student findStudent(final Long studentId) {
TypedQuery<Student> query = getEntityManager().createNamedQuery("from Student s where s.studentId =:studentId", Student.class);
query.setParameter("studentId", studentId);
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
query.setHint(JAVAX_PERSISTENCE_LOCK_TIMEOUT, ZERO_NUMBER);
return query.getSingleResult();
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void updateStudent(Student student) {
makePersistent(student);
getEntityManager().flush();
}
精彩评论