JPA 混淆(托管与非托管实体)
Posted
技术标签:
【中文标题】JPA 混淆(托管与非托管实体)【英文标题】:JPA confusion (managed vs non-managed entities) 【发布时间】:2011-11-18 01:06:34 【问题描述】:我正在做一个网络项目,试图了解一遍又一遍地做这种事情的最佳方法:
从数据库中读取对象 A 稍后,读取另一个对象 (B) 对数据库中的 A 和 B 进行更改(作为事务的一部分 - 写入所有更改或不更改)老式的 JDBC 类型的方式不是问题,但 JPA 正在努力。
我需要明确区分数据库更改发生的位置,并且根据我观察到的情况,对托管实体的任何更改都将在下次调用 EntityManager.commit()
时进行修改(无论事务是否显式是否在更改之前开始)。对吗?
那么确保所有实体从不受到管理,并且总是merge()
更好吗?
我发现自己必须在这两个示例之间做出选择:
重绘Action1
User user = getUser(); //non-managed entity
Car car = getCar(123); //non-managed
car.setColor("Red");
user.setLog("Paints car red");
dao.update(car, user);
重绘DAO1
entityTransaction.begin();
entityManager.merge(car);
entityManager.merge(user);
entityTransaction.commit();
或者:
RepaintAction2(这与 RepaintAction1 相同,但具有托管实体)
User user = getUser(); //managed entity
Car car = getCar(123); //managed
car.setColor("Red");
user.setLog("Paints car red");
dao.update(car, user);
重绘DAO2
entityTransaction.begin();
entityManager.flush();
entityTransaction.commit();
第一个我不介意,但我肯定错过了托管实体的一些优势(哪些?)。第二个我不喜欢事务范围不明确的方式(以及如何处理回滚?)。
但这些是唯一的选择吗(例如,有没有办法使用托管实体明确划分交易)?处理这个问题的最佳方法是什么?
我很抱歉花了这么长时间,但我浏览了很多没有帮助的文档,我什至不确定我所观察到的是否正确。
【问题讨论】:
我使用 spring 来管理我的事务,因此我无法回答您的主要问题,但要回答次要问题,托管实体的一个优点是能够使用惰性集合。跨度> 【参考方案1】:下次调用EntityManager.commit()
时,对托管实体的任何更改都将被修改(无论事务是否在更改之前显式开始)。 正确吗?
正确。
最好确保所有实体都不受管理,并且始终merge()
?
并非总是如此(或者他们不会留下选择余地),但这很常见,
所以示例 1 是您最常找到的。
示例 2 中的刷新并不是真正需要的,提交会隐式刷新。
如何处理回滚?如果提交失败,持久性提供程序将回滚。如果应用程序容器收到系统异常,它将回滚现有事务。
托管实体的优势?延迟加载(无 LazyInitializationException)。它还可以跟踪为您更改的内容,因此您不会合并太多/很少的实体。
有没有办法使用托管实体明确划分交易?我不清楚你不清楚什么。也许您的意思是不清楚发生了什么变化,因为实体的变化发生在开始/提交边界之外。但是对于合并分离的实体也是如此,您对合并的内容有更多的控制权,但您看不到确切的属性发生了变化。
处理此问题的最佳方法是什么? 通常,您的 Web 请求由事务性服务(spring/ejb...)处理。实体管理器将由容器注入。通常,这些实体管理器是事务范围的(仅在事务期间存在),因此在调用您的服务之前它们并不存在。这意味着传递给它们的所有实体都不受管理。事务将在服务结束时提交(或回滚)。
注意:如果您考虑使用托管实体,这通常与长期存在的 EntityManager 一起使用。如果您这样做,请注意 EntityManager 不是线程安全的。
【讨论】:
谢谢@Catweazle!这一切都回答了:)【参考方案2】:关于你的第四个问题,可以通过以下方式回滚:
-
从标记为@Transactional 的方法中引发异常
通过 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 明确告诉事务它应该回滚;
【讨论】:
以上是关于JPA 混淆(托管与非托管实体)的主要内容,如果未能解决你的问题,请参考以下文章
C# DllImport“调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配 ”