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

问题描述:

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

I'm working on a web project, trying to understand the best way to do this sort of thing over and over again:


  • 从数据库中读取对象 A

  • 稍后,阅读另一个对象( B

  • 更改数据库中的 A B (作为交易的一部分 - 写所有更改或无)

  • 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)

旧的skool JDBC类型方式不是问题,但JPA正在努力。

The old-skool JDBC-type way isn't a problem, but JPA is doing my head in.

我需要在那里明确划分数据库发生变化的位置,并且从我观察到的任何对托管实体的更改都将在下次修改 EntityManager.commit( )被调用(无论是否在更改之前显式启动了事务)。正确?

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?

确保所有实体从不管理,并始终 merge()

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();

或:

RepaintAction2 (这与 RepaintAction1 相同,但托管实体)

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.


  1. 任何改变下次调用 EntityManager.commit()时,将修改托管实体(无论是否在更改之前显式启动了事务)。 正确吗?
    正确。

  1. 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.

确保所有实体永远不会受到管理,这样做会更好吗?总是 merge()
并不总是(或者他们不会让选择打开)但是很常见,
所以示例1是你最常找到的。

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.

实际上并不需要示例2中的flush,提交将隐式刷新。

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.

托管实体的优点?延迟加载(没有LazyInitializationException) 。此外,它还会跟踪您的更改内容,因此您不会合并太少/几个实体。

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.

处理此问题的最佳方式是什么?通常,您的网络请求由交易服务处理(spring / ejb。 ..)。实体经理将由容器注入。通常,这些实体管理器是事务范围的(仅在事务发生时生效),因此在调用服务之前它们不存在。这意味着传递给它们的所有实体都不受管理。交易将在服务结束时提交(或回滚)。

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.






注意:如果您考虑使用托管实体,这通常与长期存在的EntityManagers一起使用。如果这样做,请注意EntityManagers不是线程安全的。


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.