4.4.5.3.2. Reading and Modifying Data in a Nested Transaction
Let us first have a look at a dependent nested transaction created using getTransaction()
:
void methodA() {
Transaction tx = persistence.createTransaction();
try {
EntityManager em = persistence.getEntityManager();
// (1) loading an entity with name == "old name"
Employee employee = em.find(Employee.class, id);
assertEquals("old name", employee.getName());
// (2) setting new value to the field
employee.setName("name A");
// (3) calling a method creating a nested transaction
methodB();
// (8) the changes are committed to DB, and
// it will contain "name B"
tx.commit();
} finally {
tx.end();
}
}
void methodB() {
Transaction tx = persistence.getTransaction();
try {
// (4) retrieving the same instance of EntityManager as methodA
EntityManager em = persistence.getEntityManager();
// (5) loading an entity with the same identifier
Employee employee = em.find(Employee.class, id);
// (6) the field value is the new one since we are working with the same
// persistent context, and there are no calls to DB at all
assertEquals("name A", employee.getName());
employee.setName("name B");
// (7) no actual commit is done at this point
tx.commit();
} finally {
tx.end();
}
}
Now, let us have a look at the same example with an independent nested transaction created with createTransaction()
:
void methodA() {
Transaction tx = persistence.createTransaction();
try {
EntityManager em = persistence.getEntityManager();
// (1) loading an entity with name == "old name"
Employee employee = em.find(Employee.class, id);
assertEquals("old name", employee.getName());
// (2) setting new value to the field
employee.setName("name A");
// (3) calling a method creating a nested transaction
methodB();
// (8) an exception occurs due to optimistic locking
// and commit will fail
tx.commit();
} finally {
tx.end();
}
}
void methodB() {
Transaction tx = persistence.createTransaction();
try {
// (4) creating a new instance of EntityManager,
// as this is a new transaction
EntityManager em = persistence.getEntityManager();
// (5) loading an entity with the same identifier
Employee employee = em.find(Employee.class, id);
// (6) the field value is old because an old instance of the entity
// has been loaded from DB
assertEquals("old name", employee.getName());
employee.setName("name B");
// (7) the changes are commited to DB, and the value of
// "name B" will now be in DB
tx.commit();
} finally {
tx.end();
}
}
In the last example, the exception at point (8) will only occur if the entity supports optimistic locking, i.e. if it implements Versioned
interface.