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.