JPA2乐观锁

3

你好,我在使用JPA2中的Optimistic Lock遇到了困难,但是我不知道为什么会发生这种情况。 我的情况是我正在运行多个线程,但是有一个实体在数据库中存储进度。 这意味着在执行过程中,不同的线程试图更新此实体,以便用户可以查看进度。

我有两个方法addAllItemsaddDone。 两种方法都用于由几个线程更新实体,并通过显示(done / allItems)* 100来显示结果。

最初,这些方法都很简单。

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void addAllItems(Long id, Integer items){
    Job job = jobDao.findById(id);
    job.setAll(job.getAll() + items);

    jobDao.merge(job);
}

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void addDone(Long id, Integer done){
    Job job = jobDao.findById(id);
    job.setDone(job.getDone() + done);

    jobDao.merge(job);
}

当我意识到出现乐观锁时,我在方法签名中添加了同步关键字以改变两种方法。但是这并没有效果,所以我添加了刷新(entity manager)以确保我拥有当前版本。它也没有任何不同。我还在最后增加了手动刷新,但仍然没有明显改善……

这是方法的最终版本 (addAllItems基本相同,唯一的区别在于setter):

@Transactional(propagation=Propagation.REQUIRES_NEW)
public synchronized void addDone(Long id, Integer done){
    Job job = jobDao.findById(id);
    job = jobDao.refresh(job);
    job.setDone(job.getDone() + done);

    jobDao.merge(job);
    jobDao.flush();
}

jobDao.refresh方法只是在entityManager上调用refresh。 我使用的是eclipselink 2.40。

还有什么可以检查的吗? 目前我已经没有更多的想法了...


也许你应该在作业上使用悲观锁? - Sami Korhonen
错误发生在哪个实体上?真的是Job吗?你能展示一下Job中的alldone是什么吗? - Serge Ballesta
@SergeBallesta Job实体发生错误。all和done只是整数。以下是日志行:javax.persistence.OptimisticLockException: Exception [EclipseLink-5006] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.OptimisticLockException Exception Description: The object [com.hg.entity.Job@98] cannot be updated because it has changed or been deleted since it was last read. Class> com.hg.entity.Job Primary Key> 152 - wojtek
еӯҳеңЁд»ЈзҗҶпјҡ [com.hg.service.JobServiceImpl$$FastClassByCGLIB$$188a7e8c.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)]жҲ‘д»ҘеүҚд»ҺжңӘдҪҝз”ЁиҝҮжӮІи§Ӯй”Ғ...жҳҜеҗҰеҸҜиғҪд»…й’ҲеҜ№дёҖдёӘе®һдҪ“пјҲеңЁиҝҷз§Қжғ…еҶөдёӢдёәJobпјүдҪҝз”Ёе®ғпјҹ - wojtek
在DAO中如何获取entityManager,以及您的调用有多同步?乐观锁定防止addAllItems和addDone中的更改同时发生,因此我不确定为什么您要避免它。乐观锁定的目的是为您提供指示,即您的更改正在发生在过时的数据上-然后您可以选择重试事务。如果您切换到使用同步块或悲观锁定,则会减慢并限制应用程序。两个选项都有优点;您需要查看您的用例,而不仅仅是尝试避免异常。 - Chris
显示剩余2条评论
1个回答

1

假设你已经确认使用了代理(我假设您正确配置了PlatformTransactionManager),则可以尝试在事务内使用显式悲观锁定——通常情况下不需要这样做,但如果它能解决问题……

我猜想在您的dao中会有类似以下代码:

Job job = EntityManager.find(Job.class, jobId);

要强制进行悲观锁定,只需将其更改为:

Job job = EntityManager.find(Job.class, jobId, LockModeType.PESSIMISTIC_WRITE);

如果你只是进行加载、修改、存储和提交操作,那么悲观锁可能是一个正确的使用案例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接