Вложенные транзакции
От: sgp  
Дата: 13.04.15 15:50
Оценка:
Добрый день, коллеги!


Попробовал Spring Data JPA. Столкнулся с следующей проблемой.
После выполнения метода testTransaction, в БД появляется новая запись. Я ожидал, что транзакция будет откачена.

public class TestService {
    @Autowired
    private JpaRepository<User, String> userRepository;

    @Transactional
    void testTransaction(){
        User user = new User("Tom");
        userRepository.save(user);
        throw new RuntimeException("Test exception");
    }
}


Правильно ли я понимаю, что методы JpaRepository всегда выполняются во вложенной транзакции и результаты выполнения этих методов фиксируются независимо от внешней транзакции?

Спасибо!
Re: Вложенные транзакции
От: andyag  
Дата: 13.04.15 16:37
Оценка:
Здравствуйте, sgp, Вы писали:

sgp>После выполнения метода testTransaction, в БД появляется новая запись. Я ожидал, что транзакция будет откачена.


Рискну предположить, что вы просто что-то недонастроили и транзакции на самом деле нет.
Re[2]: Вложенные транзакции
От: sgp  
Дата: 13.04.15 17:04
Оценка:
Здравствуйте, andyag, Вы писали:

A>Здравствуйте, sgp, Вы писали:


sgp>>После выполнения метода testTransaction, в БД появляется новая запись. Я ожидал, что транзакция будет откачена.


A>Рискну предположить, что вы просто что-то недонастроили и транзакции на самом деле нет.



Ну если данные сохранились в базе, то транзакция, наверное, все таки есть.
Однако я вполне допускаю, что что-то недонастроил. Есть идеи куда глянуть?


Спасибо
Re[3]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 13.04.15 17:13
Оценка:
Здравствуйте, sgp, Вы писали:

sgp>Есть идеи куда глянуть?

В логи и в спринговый Transaction Manager.
Re[4]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 07:39
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sgp, Вы писали:


sgp>>Есть идеи куда глянуть?

B>В логи и в спринговый Transaction Manager.

Продолжая тему вложенных транзакций появился еще вопрос. Есть 2 фрагмента кода:

// Случай 1
public class TestService {
    @Autowired
    private JpaRepository<User, String> userRepository;

    @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.SERIALIZABLE)
    void testTransaction(){
        User user = userRepository.findOne("Tom");
    user.setAge(20);
        userRepository.save(user);
    }
}
// Случай 2
public class TestServiceEm {
    @PersistenceContext(unitName="default")
    EntityManager em;

    @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.SERIALIZABLE)
    void testTransaction(){
        User user = em.find("Tom");
    user.setAge(25);
        em.merge(user);
    }
}


В первом случае открывается транзакция при входе в метод TestService.testTransaction, после чего вызовы методов userRepository выполняется в отдельных вложенных транзакциях.
Во втором случае все вызовы к EntityManager в теле метода TestServiceEm.testTransaction() выполняется в рамках одной транзакции.

Подскажите, пожалуйста, можно ли добиться что бы несколько вызовов JpaRepository в пределах одного метода сервисного класса выполнялись в рамках одной транзакции?

Спасибо.
Re[5]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 14.04.15 07:56
Оценка:
Здравствуйте, sgp, Вы писали:

sgp>Продолжая тему вложенных транзакций появился еще вопрос. Есть 2 фрагмента кода:

Мне сейчас некогда вникать. Но была вот такая вот офигезная статья по теме:
http://www.k-press.ru/cs/2009/1/ts/ts.asp
Re[6]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 09:16
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sgp, Вы писали:


sgp>>Продолжая тему вложенных транзакций появился еще вопрос. Есть 2 фрагмента кода:

B>Мне сейчас некогда вникать. Но была вот такая вот офигезная статья по теме:
B>http://www.k-press.ru/cs/2009/1/ts/ts.asp

Спасибо, статья познавательная, но, к сожалению, не содержащая ответ на вопрос почему в случае с JpaRepository его методы вызываются во вложенных транзакциях.
Re[5]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 14.04.15 09:50
Оценка:
Здравствуйте, sgp, Вы писали:


sgp> @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.SERIALIZABLE)

Зачем тут SERIALIZABLE?

sgp>после чего вызовы методов userRepository выполняется в отдельных вложенных транзакциях.

Как это было определено? Может проблема в том что внешний транзакции небыло по какой-то причине?
Re[6]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 10:48
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sgp, Вы писали:



sgp>> @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.SERIALIZABLE)

B>Зачем тут SERIALIZABLE?


В данном случае SERIALIZABLE установлена, что бы хорошо было видно отличие в работе первого и второго фрагмента кода.
Для первого фрагмента кода, при исполнении 2 конкурентных транзакций, обе выполнятся успешно, независимо от уровня изоляции транзакций.
Для второго фрагмента кода, при исполнении 2 конкурентных транзакций, одна из транзакций завершится успешно, а вторая завершится исключением, только в случае уровня изоляции SERIALIZABLE. Как раз такое поведение я и ожидаю, как от первого фрагмента так и от второго.


sgp>>после чего вызовы методов userRepository выполняется в отдельных вложенных транзакциях.

B>Как это было определено? Может проблема в том что внешний транзакции небыло по какой-то причине?

Путем пошаговой трассировке в отладчике.

Поставил точки останова в TransactionAspectSupport.invokeWithinTransaction
одну перед началом транзакции:
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
вторую на фиксации транзакции
commitTransactionAfterReturning(txInfo);

и пронаблюдал, что в первом случае я попадаю в TransactionAspectSupport.invokeWithinTransaction 1 раз при входе/выходе из testTransaction и по одному разу на каждый из вызовов
— User user = userRepository.findOne("Tom");
— userRepository.save(user);

тогда как во втором случае открытие и закрытие транзакции в методе TransactionAspectSupport.invokeWithinTransaction происходит однократно. Транзакция открывается при вызове метода TestServiceEm.testTransaction и закрывается при возврате из него.
Re[7]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 14.04.15 10:59
Оценка:
Здравствуйте, sgp, Вы писали:

sgp>одну перед началом транзакции:

sgp> TransactionInfo txInfo = createTransaction IfNecessary(tm, txAttr, joinpointIdentification);
Это не обязательно начало новой транзакции.
Re: Вложенные транзакции
От: DrDred Россия  
Дата: 14.04.15 11:49
Оценка:
Здравствуйте, sgp, Вы писали:

А как данный метод вызывается? Насколько я помню, если создавать объект напрямую, не через Spring, и работать не через интерфейс, то прокси-объект не создается, и соответственно аннотация не работает.
--
WBR, Alexander
Отредактировано 14.04.2015 11:58 Blazkowicz . Предыдущая версия .
Re[2]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 14.04.15 11:57
Оценка:
Здравствуйте, DrDred, Вы писали:

DD>А как данный метод вызывается? Насколько я помню, если создавать объект напрямую, не через Spring, и работать не через интерфейс, то прокси-объект не создается, и соответственно аннотация не работает.

Autowired же как-то работает.
Re[8]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 11:59
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sgp, Вы писали:


sgp>>одну перед началом транзакции:

sgp>> TransactionInfo txInfo = createTransaction IfNecessary(tm, txAttr, joinpointIdentification);
B>Это не обязательно начало новой транзакции.

В общем случае это не обязательно начало новой транзакции, но в моем случае, начинается именно новая транзакция, атрибуты которой отличаются от указанных мною. Даже если бы я не видел атрибутов, то по поведению, я вижу, что это новая транзакция.
Ведь я ожидаю отлуп для одной из конкурентных транзакций меняющих одну и ту же строку в БД, а получаю в случае с JpaRepository успешное выполнение обоих транзакций, и потерю обновления одной из них.
Re[3]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 12:02
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, DrDred, Вы писали:


DD>>А как данный метод вызывается? Насколько я помню, если создавать объект напрямую, не через Spring, и работать не через интерфейс, то прокси-объект не создается, и соответственно аннотация не работает.

B>Autowired же как-то работает.

Естественно, экземпляры EntityManager и JpaRepository я получаю от спринга. Ну и попадание в TransactionAspectSupport подтверждает, что прокси создан и работает.
Re[9]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 14.04.15 12:07
Оценка:
Здравствуйте, sgp, Вы писали:

sgp>В общем случае это не обязательно начало новой транзакции, но в моем случае, начинается именно новая транзакция, атрибуты которой отличаются от указанных мною. Даже если бы я не видел атрибутов, то по поведению, я вижу, что это новая транзакция.

У меня есть сильные сомнения на этот счет.

sgp>Ведь я ожидаю отлуп для одной из конкурентных транзакций меняющих одну и ту же строку в БД, а получаю в случае с JpaRepository успешное выполнение обоих транзакций, и потерю обновления одной из них.

С какой радости должен быть отлуп?
Re[10]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 12:15
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sgp, Вы писали:


sgp>>В общем случае это не обязательно начало новой транзакции, но в моем случае, начинается именно новая транзакция, атрибуты которой отличаются от указанных мною. Даже если бы я не видел атрибутов, то по поведению, я вижу, что это новая транзакция.

B>У меня есть сильные сомнения на этот счет.

Как я могу их равеять или подтвердить? У меня идеи кончились, к сожалению.

sgp>>Ведь я ожидаю отлуп для одной из конкурентных транзакций меняющих одну и ту же строку в БД, а получаю в случае с JpaRepository успешное выполнение обоих транзакций, и потерю обновления одной из них.

B>С какой радости должен быть отлуп?

Ну как с какой радости?
2 конкурентные транзакции с уровнем изоляции SERIALIZABLE, меняют одно и тоже поле одной и той же записи в БД. Одна должна исполнится успешно, другая должна потерпеть крушение.
Re[11]: Вложенные транзакции
От: Blazkowicz Россия  
Дата: 14.04.15 12:35
Оценка:
Здравствуйте, sgp, Вы писали:

sgp>2 конкурентные транзакции с уровнем изоляции SERIALIZABLE, меняют одно и тоже поле одной и той же записи в БД. Одна должна исполнится успешно, другая должна потерпеть крушение.

Во-первых так ведет себя Optimistic Lock и без всяких Serializable изоляций. А Serializable гарантирует максимальную изоляцию конкуренции вплоть до того что транзакции будут выполнены последовательно. Возможно речь о какой-то конкретной фиче какой-то конкретной БД?
Во-вторых чем именно этот код гарантирует что транзакции конкурентные?
Re[12]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 12:57
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, sgp, Вы писали:


sgp>>2 конкурентные транзакции с уровнем изоляции SERIALIZABLE, меняют одно и тоже поле одной и той же записи в БД. Одна должна исполнится успешно, другая должна потерпеть крушение.

B>Во-первых так ведет себя Optimistic Lock и без всяких Serializable изоляций. А Serializable гарантирует максимальную изоляцию конкуренции вплоть до того что транзакции будут выполнены последовательно. Возможно речь о какой-то конкретной фиче какой-то конкретной БД?
B>Во-вторых чем именно этот код гарантирует что транзакции конкурентные?

Уровень изоляции SERIALIZABLE не допускает одновременное изменение одного поля одной записи двумя конкурирующими транзакциями. Если такое случается, то одна из транзакций должна быть откачена. В моем случае используется Oracle. Абсолютно точно так ведет себя Postgres и Sybase. Похожим образом должны вести себя и другие СУБД.

Что касается уверенности в конкурентности транзакции, то я не вижу причины в этом сомневаться.
Если я ручками открываю 2 сессии к БД и в пошаговом режиме выполняю чтение и обновление записей, то почему я должен сомневаться в том, что транзакции конкурентны?


Спасибо
Re: Вложенные транзакции
От: . Великобритания  
Дата: 14.04.15 19:51
Оценка:
Здравствуйте, sgp, Вы писали:


sgp> Правильно ли я понимаю, что методы JpaRepository всегда выполняются во вложенной транзакции и результаты выполнения этих методов фиксируются независимо от внешней транзакции?

А autocommit у datasource случайно не стоит?
avalon/1.0.432
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: Вложенные транзакции
От: sgp  
Дата: 14.04.15 21:02
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, sgp, Вы писали:



sgp>> Правильно ли я понимаю, что методы JpaRepository всегда выполняются во вложенной транзакции и результаты выполнения этих методов фиксируются независимо от внешней транзакции?

.>А autocommit у datasource случайно не стоит?

Думаю, нет. Ведь в моих тестах EntityManager и JpaRepository работают с одним источником данных.
Однако обязательно проверю, настройки автокомита.

Спасибо
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.