JPA 混淆(托管实体与非托管实体)
我正在开发一个网络项目,试图了解一遍又一遍地执行此类操作的最佳方法:
- 从数据库读取对象 A
- 稍后,读取另一个对象 (B )
- 对数据库中的 A 和 B 进行更改(作为事务的一部分 - 写入所有更改或不写入任何更改
) old-skool JDBC 类型的方式不是问题,但 JPA 正在困扰我 我需要对数据库更改发生的位置有一个明确的划分,并且根据我的观察,对托管实体的
任何更改都将在下次调用 EntityManager.commit() 时进行修改(无论事务是否在更改之前明确开始)。正确的?
那么确保所有实体从不都受到管理,并且始终merge()
是不是更好?
我发现自己必须在这两个示例之间做出决定:
RepaintAction1
User user = getUser(); //non-managed entity
Car car = getCar(123); //non-managed
car.setColor("Red");
user.setLog("Paints car red");
dao.update(car, user);
RepaintDAO1
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);
RepaintDAO2
entityTransaction.begin();
entityManager.flush();
entityTransaction.commit();
第一个我不介意,但我必须错过托管实体的一些优势(哪些优势?)。在第二种情况下,我不喜欢事务范围不明确的方式(以及如何处理回滚?)。
但这些是唯一的选择吗(例如,有没有一种方法可以使用托管实体明确划分事务)?处理这个问题的最佳方法是什么?
我很抱歉写了这么长,但我已经阅读了很多没有帮助的文档,我什至不确定我所观察到的是否正确。
I'm working on a web project, trying to understand the best way to do this sort of thing over and over again:
- Read object A from the DB
- Later on, read another object (B)
- Make changes to A and B in the DB (as part of a transaction - write all the changes or none)
The old-skool JDBC-type way isn't a problem, but JPA is doing my head in.
I need there to be a clear demarcation as to where the DB changes occur, and from what I've observed any changes to managed entities will be modified the next time EntityManager.commit()
is called (no matter if a transaction was explicitly begun before the changes or not). Correct?
Is it better then to make sure all entities are never managed, and always merge()
?
I find myself having to decide between these two examples:
RepaintAction1
User user = getUser(); //non-managed entity
Car car = getCar(123); //non-managed
car.setColor("Red");
user.setLog("Paints car red");
dao.update(car, user);
RepaintDAO1
entityTransaction.begin();
entityManager.merge(car);
entityManager.merge(user);
entityTransaction.commit();
Or:
RepaintAction2 (this is the same as RepaintAction1, but with managed entities)
User user = getUser(); //managed entity
Car car = getCar(123); //managed
car.setColor("Red");
user.setLog("Paints car red");
dao.update(car, user);
RepaintDAO2
entityTransaction.begin();
entityManager.flush();
entityTransaction.commit();
The first I don't mind, but I must be missing some advantages to managed entities (which ones?). In the second I don't like the way the scope of transactions is not clear (and how is a rollback handled?).
But are these the only options (e.g. is there a way to clearly demarcate transactions using managed entities)? What is the best way to handle this?
I apologise for making this long, but I've gone through a lot of documentation that hasn't helped and I'm not even sure that what I'm observing is correct.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对托管实体的任何更改都将在下次调用 EntityManager.commit() 时进行修改(无论事务是否在更改之前显式开始)。 正确吗?
正确。
确保所有实体从不被管理并且始终
merge()
是不是更好?并非总是如此(或者他们不会留下选择余地),但这是常见的,
因此,示例 1 是您最常发现的内容。
示例 2 中的刷新并不是真正需要的,提交将隐式刷新。
如何处理回滚?如果提交失败,持久性提供程序将回滚。如果应用程序容器收到系统异常,它将回滚现有事务。
托管实体的优点?延迟加载(无 LazyInitializationException)。它还会跟踪您所做的更改,因此您不会合并太多/太少的实体。
有没有一种方法可以使用托管实体清楚地划分事务?我不清楚你不清楚什么。也许您的意思是不清楚发生了什么变化,因为实体的更改发生在开始/提交边界之外。但对于合并分离的实体来说也是如此,您对合并的内容有更多的控制权,但您无法确切地看到哪些属性发生了更改。
处理这个问题的最佳方法是什么?通常,您的 Web 请求由事务性服务(spring/ejb...)处理。实体管理器将由容器注入。通常,这些实体管理器是事务范围的(仅在事务期间有效),因此它们在调用您的服务之前并不存在。这意味着传递给它们的所有实体都不受管理。事务将在服务结束时提交(或回滚)。
注意:如果您考虑使用托管实体,这通常与长期存在的 EntityManager 相匹配。如果您这样做,请注意 EntityManager 不是线程安全的。
Any changes to managed entities will be modified the next time
EntityManager.commit()
is called (no matter if a transaction was explicitly begun before the changes or not). Correct?Correct.
Is it better then to make sure all entities are never managed, and always
merge()
?Not always (or they would not leave the choice open) but it is common,
so example 1 is what you'll find mostly.
The flush in example 2 is not really needed, the commit will implicitly flush.
How is rollback handled? If the commit fails, the persistence provider will roll back. An application container will rollback existing transactions if it receives a system exception.
Advantages of managed entities? Lazy loading (no LazyInitializationException). Also it keeps track of what's changed for you, so you do not merge too much/few entities.
Is there a way to clearly demarcate transactions using managed entities? It is not clear to me what is not clear to you. Maybe you mean that it is not clear to see what has changed because the changes to the entities happen outside the begin/commit boundaries. But that's true for merging detached entities as well, you have a little more control over what you merge, but you do not see exactly which attributes are changed.
What's the best way to handle this? Typically your web requests are handled by a service that is transactional (spring/ejb...). Entity managers will be injected by the container. Typically these Entity managers are transaction scoped (only live for the time of the transaction), so they did not exist before your service was called. This implies that all entities passed to them are not managed. The transaction will commit (or roll back) at the end of the service.
Note: if you think about using managed entities this often goes with long lived EntityManagers. If you do this, mind that EntityManagers are not thread safe.
关于您的第四个问题,可以通过以下方式进行回滚:
With regards to your fourth question, rollback can be done by the following approaches: