Рассмотрим сначала зависимую вложенную транзакцию, создаваемую через 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
.