Dav*_*est 10 java concurrency hibernate jpa
这似乎经常出现,但我用Google搜索无济于事.
假设你有一个Hibernate实体User.您User的数据库中有一个ID为1.
你有两个运行的线程,A和B.它们执行以下操作:
closesSessiondelete它Session和merge的用户1我的所有测试都表明merge尝试在数据库中找到用户1(显然不能),因此它会插入一个id为2的新用户.
另一方面,我的期望是Hibernate会看到合并的用户不是新的(因为它有一个ID).它会尝试在DB中找到失败的用户,因此不会尝试插入或更新.理想情况下,它会抛出某种并发异常.
请注意,我使用乐观锁定@Version,这无济于事.
所以,问题:
mergeJPA EntityManager而不是Hibernate 时是否有相同的行为Session?我一直在研究 JSR-220,声称Session#merge 可以从中获取其语义。遗憾的是,我发现 JSR 含糊不清。
它确实说:
乐观锁定是一种技术,用于确保仅当自读取实体状态以来没有干预事务更新该数据时,才会对与实体状态相对应的数据库数据进行更新。
如果您将“更新”包括数据库数据的一般突变(包括删除),而不仅仅是 SQL UPDATE,我认为您可以提出一个论点,即观察到的行为不符合乐观锁定。
考虑到对我的问题的评论以及随后发现的这个错误,很多人都同意。
从纯粹实用的角度来看,这种行为,无论是否合规,都可能导致相当多的错误,因为它与许多开发人员的期望相反。似乎没有一个简单的解决办法。事实上,Spring Data JPA 似乎完全忽略了这个问题,盲目使用EM#merge. 也许其他 JPA 提供商会以不同的方式处理此问题,但对于 Hibernate,这可能会导致问题。
我实际上正在通过使用Session#updatecurrent 来解决这个问题。它真的很难看,并且当您尝试update分离实体并且已经有它的托管副本时,需要代码来处理这种情况。但是,它也不会导致虚假插入。