嗨,我在和JPA2上的乐观锁做斗争,我不知道为什么会这样。
我的例子是我运行多个线程,但是数据库中有一个实体存储进程。这意味着不同的线程在执行期间尝试更新此实体,以便能够按用户查看进度。
我有一个方法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);
}

当我意识到乐观锁正在发生时,我通过将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);

正如您只需加载、修改、存储和提交一样,这可能是悲观锁定的正确用例。

09-25 20:56