Spring транзакция не откатывается в Hibernate StaleObjectStateException

У меня есть сценарий, как показано ниже

methodA(){

try{
  objB.methodB();
}
catch(Exception ex){
  log(exception caught);
}

@Transactional(value = "txManager", propagation = Propagation.REQUIRES_NEW,rollbackFor={Exception.class, StaleObjectStateException.class})
methodB(){
   methodC();
}

@Transactional(value = "txManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,StaleObjectStateException.class})
methodC(){
  /*Some logic that throws HOLF/SOSE exception. Essentially calling merge on entity that has @Version enabled
}

Моя проблема в том, что для данного потока у меня может быть два запроса, вызывающих этот метод одновременно. Я ожидаю, что methodC выдаст исключение для сбоя оптимистической блокировки и откат транзакции.

Мое ожидание было:

Допустим, у меня есть два запроса R1 и R2 R1 и R2 вызывают методA -> methodB (запускает новую транзакцию) -> methodC (транзакция распространяется): оба читают одну и ту же версию объекта, оба вносят одинаковые изменения и вызывают слияние -> methodC завершает поток обратно to methodB -> methodB завершает принудительную фиксацию транзакции -> фиксация транзакции вызывает session.flush, получает исключение времени выполнения для оптимистической блокировки и откатывается.

Я получаю исключение SOSE в методе A, я вижу его в своих регистраторах, но транзакция зафиксирована, и обе записи сохраняются.

Происходит следующее: R1 и R2 вызывают methodA -> methodB (запускает новую транзакцию) -> methodC (транзакция распространяется): оба читают одну и ту же версию объекта, оба вносят одинаковые изменения и вызывают слияние -> methodC завершает поток обратно в methodB - > methodB завершает принудительную фиксацию транзакции -> транзакция фиксируется -> генерирует исключение времени выполнения для оптимистической блокировки НЕ откатывается, и исключение перехватывается методом methodA.

Если я явно выбрасываю исключение в methodC, транзакция откатывается.

Я не уверен, почему он не откатывает транзакцию, когда возникает исключение сбоя блокировки Optimisitc.

пожалуйста, порекомендуйте


person varkashy    schedule 01.02.2018    source источник
comment
Вы получаете исключение для запросов R1 и R2 или только для R2?   -  person tsolakp    schedule 01.02.2018
comment
Это спорадически. Что когда-либо сначала обновляет объект, для второго я получаю исключение. Но запись все равно совершена   -  person varkashy    schedule 01.02.2018
comment
Хорошо, если обновление thirst завершится без ошибок, тогда оно зафиксирует изменение?   -  person tsolakp    schedule 01.02.2018
comment
обе транзакции независимы. Допустим, у моей существующей записи есть версия 1. Когда R1 и R2 приходят, оба читают версию 1. R1 обновляет запись, и теперь версия 2. Когда R2 пытается обновить, у него есть версия 1, но у db есть версия 2, поэтому я получу исключение устаревшего объекта. и запись не должна сохраняться. Однако сейчас я вижу 3 записи в БД. Один из R1 и один из R2 и старая запись, которая была обновлена. Что касается оптимистичной блокировки, я ожидал отката транзакции для R2. Я что-то упускаю?   -  person varkashy    schedule 01.02.2018
comment
Тяжело сказать. Возможно, вы разместите образец кода для methodC, и мы сможем вам помочь.   -  person tsolakp    schedule 01.02.2018
comment
Логика проста. Допустим, моя сущность - это TableA с флагом, который может быть установлен «Y» или «N». метод C будет иметь логику, как показано ниже TableA clone = originalObj; originalObj.setFlag ('N'); слияние (originalObj); слияние (cloneObj);   -  person varkashy    schedule 01.02.2018
comment
Какая у вас конфигурация пружины? В частности, какова <aop> конфигурация? Ваш компонент проксируется через интерфейс или через CGLib?   -  person M. Prokhorov    schedule 01.02.2018
comment
не используя aop. конфигурация пружины, как показано ниже <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <qualifier value="txManager"/> </bean> <tx:annotation-driven transaction-manager="txManager" />   -  person varkashy    schedule 01.02.2018
comment
Как я уже сказал, у меня есть исключение. Но это не откат транзакции   -  person varkashy    schedule 01.02.2018
comment
Я просто что-то пробовал. Кажется, что если я явно вызываю session.flush () в methodC, он генерирует исключение времени выполнения, и транзакция откатывается. Я предполагаю, что проблема может быть в распространении транзакции, так как в этом случае он вызывает сброс после завершения методаB и каким-то образом он все же фиксируется   -  person varkashy    schedule 01.02.2018


Ответы (1)


Хорошо .. Так что, похоже, это работает. Оказывается, проблема в провайдере JTA. Я развертывал код на Tomee, это гарантирует, что Spring выберет поставщика из библиотеки tomcat, и он использовал Gerenimo, который, похоже, не обрабатывает откат. Я вставил тот же код в weblogic и использовал org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform в качестве поставщика JTA, похоже, это работает, как ожидалось. Отправлю сообщение, если я узнаю причину, по которой Gerenimo не работает, или если что-то мне не хватает.

person varkashy    schedule 01.02.2018