Рассмотрим сначала зависимую вложенную транзакцию, создаваемую через getTransaction():
void methodA() {
Transaction tx = persistence.createTransaction();
try {
EntityManager em = persistence.getEntityManager();
// (1) загружаем сущность, в которой name == "old name"
Employee employee = em.find(Employee.class, id);
assertEquals("old name", employee.getName());
// (2) присваиваем новое значение полю
employee.setName("name A");
// (3) вызываем метод, создающий вложенную транзакцию
methodB();
// (8) здесь происходит коммит изменений в БД, и в ней
// окажется значение "name B"
tx.commit();
} finally {
tx.end();
}
}
void methodB() {
Transaction tx = persistence.getTransaction();
try {
// (4) получаем тот же экземпляр EntityManager, что и methodA
EntityManager em = persistence.getEntityManager();
// (5) загружаем сущность с тем же идентификатором
Employee employee = em.find(Employee.class, id);
// (6) значение поля новое, т.к. мы работаем с тем же
// персистентным контекстом, и обращения к БД вообще
// не происходит
assertEquals("name A", employee.getName());
employee.setName("name B");
// (7) в этот момент реально коммита не происходит
tx.commit();
} finally {
tx.end();
}
}Теперь рассмотрим тот же самый пример с независимой вложенной транзакцией, создаваемой через createTransaction():
void methodA() {
Transaction tx = persistence.createTransaction();
try {
EntityManager em = persistence.getEntityManager();
// (1) загружаем сущность, в которой name == "old name"
Employee employee = em.find(Employee.class, id);
assertEquals("old name", employee.getName());
// (2) присваиваем новое значение полю
employee.setName("name A");
// (3) вызываем метод, создающий вложенную транзакцию
methodB();
// (8) здесь возникнет исключение из-за оптимистичной блокировки
// и коммит не пройдет вообще
tx.commit();
} finally {
tx.end();
}
}
void methodB() {
Transaction tx = persistence.createTransaction();
try {
// (4) создается новый экземпляр EntityManager, т.к. это
// новая транзакция
EntityManager em = persistence.getEntityManager();
// (5) загружаем сущность с тем же идентификатором
Employee employee = em.find(Employee.class, id);
// (6) значение поля старое, т.к. произошла загрузка из БД
// старого экземпляра сущности
assertEquals("old name", employee.getName());
employee.setName("name B");
// (7) здесь происходит коммит изменений в БД, и в ней
// окажется значение "name B"
tx.commit();
} finally {
tx.end();
}
}В последнем случае исключение в точке (8) возникнет, только если сущность является оптимистично блокируемой, т.е. если она
реализует интерфейс Versioned.

