Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA confusion (managed vs non-managed entities)

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.

like image 494
Ivan Maeder Avatar asked Sep 15 '11 16:09

Ivan Maeder


1 Answers

  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.

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

  3. The flush in example 2 is not really needed, the commit will implicitly flush.

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

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

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

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

like image 159
Catweazle Avatar answered Nov 18 '22 12:11

Catweazle