JPA 1.0 和 Hibernate 3.4 在锁定时生成 FOR UPDATE NOWAIT

发布于 2024-11-08 23:44:48 字数 940 浏览 0 评论 0原文

我目前正在开发一个部署到 Weblogic 10.3.3 的 Java EJB 项目。我们使用 JPA 1.0 和 Hibernate 3.4 作为实现者。我们还使用 Oracle10g Dialect。

我们遇到的问题涉及在尝试锁定行进行更新时由 hibernate 生成 SQL。

我们执行一个查询:

Query q = entityManager.createNamedQuery("findMyObject");    
MyHibernateObject myObject= (MyHibernateObject ) q.getSingleResult();

然后用以下方法锁定该对象:

entityManager.lock(myObject, LockModeType.WRITE);

这种锁定行为会生成查询:

SELECT myObject FROM myTable FOR UPDATE NOWAIT

我希望它生成的是:

SELECT myObject FROM myTable FOR UPDATE

使其他线程能够查询该对象而不抛出异常: org.hibernate.exception.LockAcquisitionException 并只需等待轮到他们或让 EJB 事务超时。

那么知道了这一切,我可以强制 Hibernate 生成不带 NOWAIT 关键字的 SQL 吗?

我知道使用 Hibernate 3.6 和 JPA 2.0 将允许使用悲观锁,但由于 Weblogic 仅支持 JPA 1.0,我们的手被束缚了。

理想情况下,当我需要的只是增加 EntityManager 创建锁时 Hibernate 生成的 SQL 时,我希望通过处理异常来避免编写我们自己的重试和/或超时机制。

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();

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

国产ˉ祖宗 2024-11-15 23:44:48

好的,我们正在使用一种解决方法,直到更新到 Weblogic 10.3.4。

这是为了防止其他人偶然发现这一点:

SessionImpl session = (SessionImpl)entityManager.getDelegate();
session.lock(myObject, LockMode.UPGRADE);

这当然违反了 JPA 标准,因为我们公开了 hibernate 实现并使用 hibernate 会话。

但它会产生一个

SELECT myObject FOR UPDATE

而不是

SELECT myObject FOR UPDATE NOWAIT

希望这可以帮助某人。

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.

静赏你的温柔 2024-11-15 23:44:48

使用下面的代码可以跳过锁定的行。这是替代的

从学生中选择 *,其中学生 id = n 立即更新

如果行已被锁定,findStudnt 方法将引发错误。如果没有错误,则调用 updateStudent 方法来更新学生实体,否则记录错误以供审核。

@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();
}

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文