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