关于线程安全和JPA EntityManager

3
假设我们有两个相互依赖的实体并为每个实体设置了DAO。
Entity1 -> * Entity2
Entity2 

现在假设我们有两个线程从数据库中获取数据,Thread1要求Entity1Dao获取某些具有依赖字段初始化的对象,同时Thread2尝试使用Entity2Dao获取已检索的相同Entity2对象。
Entity1Dao创建EntityManager(em1)并检索数据,而Entity2Dao将创建不同的EntityManager(em2)以从数据库中获取查询对象。
问题: em2是否保持锁定直到em1关闭?如果没有,我们应该在“包含请求对象的其他entitymanager”上获得异常吗?
2个回答

4

不行。每个EntityManager将返回实体的不同实例。

并发事务将有可能写入相同的行,最后一个事务会获胜,除非您实现了乐观锁定(通过为实体添加@Version字段)。


谢谢您的回答,您能否也回答一下这个问题呢?假设我从实体管理器中获取了一些对象(附加),然后关闭了em,那么这个对象还会保持附加状态吗? - vach
不,如果您关闭 em,则所有由 em 管理的对象都将变为未管理状态。 - JB Nizet
我正在尝试为我的应用程序实现数据访问层,而我发现使其线程安全的唯一方法是在每个事务中使用entityManager,因此正如你所说,从dao返回的任何对象都将变为未托管状态。有更好的方法来做到这一点吗? - vach
起初,我尝试保持我的实体管理器处于活动状态并重复使用它们,但很快我就遇到了异常,例如“实体已经被另一个实体管理器加载”,不确定该怎么办?您能推荐一些相关文献吗? - vach
2
事务不应该由数据访问层启动和提交。使用Java EE或Spring在服务层为您声明式地处理事务,或重新发明它们(但我会避免这样做)。 - JB Nizet
谢谢,看来我对JPA的工作方式和事务管理有误解... - vach

3
实体管理器在这种情况下是完全独立的。JPA 提供了乐观锁悲观锁的机制,您可以使用它们来协调两个事务处理相同数据时应该发生什么。
请参阅JPA 2.1规范第3.4节中的锁定和并发性。

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