JPA 混淆(托管与非托管实体)

Posted

技术标签:

【中文标题】JPA 混淆(托管与非托管实体)【英文标题】:JPA confusion (managed vs non-managed entities) 【发布时间】:2011-11-18 01:06:34 【问题描述】:

我正在做一个网络项目,试图了解一遍又一遍地做这种事情的最佳方法:

从数据库中读取对象 A 稍后,读取另一个对象 (B) 对数据库中的 AB 进行更改(作为事务的一部分 - 写入所有更改或不更改)

老式的 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# 托管与非托管

sql SQL:SMP托管与非托管计数

C# DllImport“调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配 ”

[转]托管代码与非托管代码

Net Framework 中托管代码与非托管代码的区别