嗨,我在和JPA2上的乐观锁做斗争,我不知道为什么会这样。
我的例子是我运行多个线程,但是数据库中有一个实体存储进程。这意味着不同的线程在执行期间尝试更新此实体,以便能够按用户查看进度。
我有一个方法addAllItems
和addDone
。这两种方法都用于通过多个线程更新实体,我通过显示(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);
}
当我意识到乐观锁正在发生时,我通过将synchronized添加到签名更改了这两个方法。它没有效果,所以我添加了refresh(来自实体管理器)以确保我有当前版本。这也没什么区别。我还添加了手动冲洗结束,但仍然没有更好的…
这是方法的最终版本(
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
方法只是调用refresh onentityManager
。我用的是日食线2.40。
我还能查什么?
我现在没主意了…
最佳答案
当您确定您正在使用代理时(我假设您正确配置了PlatformTransactionManager
),您可以尝试在事务中使用显式悲观锁-通常您不需要这样做,但如果它解决了问题…
我想在你的刀里,你有这样的东西:
Job job = EntityManager.find(Job.class, jobId);
要强制执行悲观锁,只需将其更改为:
Job job = EntityManager.find(Job.class, jobId, LockModeType.PESSIMISTIC_WRITE);
正如您只需加载、修改、存储和提交一样,这可能是悲观锁定的正确用例。