Почему исключение перехватывается, но транзакция все равно откатывается?

Java

Я разместил это на днях"Позвольте задать вопрос: Будет ли откатываться эта транзакция? 》Я получил много хороших отзывов, и многие читатели дали мне несколько ответов о test4 через WeChat, группу или по электронной почте. Есть также тестовые примеры, отправленные непосредственно мне, чтобы доказать, что мой ответ неверен. Сегодня давайте рассмотрим спорный вопрос test4. Если вы только что открыли эту статью и не знаете, о чем мы говорим, вы можете нажать, чтобы просмотреть предыдущую."Позвольте задать вопрос: Будет ли откатываться эта транзакция? 》. Я считаю, что благодаря анализу этих двух статей вы совершите качественный скачок в механизме выполнения транзакций в Spring Data JPA.

Почему ты не откатился

Сначала поговорим о тех случаях, когда проверка кода **"не будет откатана"**, объясним сначала причины этих неверных ответов, а затем подробно остановимся на ситуации, когда будет откатываться test4.

Согласно случаям или четким описаниям, данным мне читателями за последние два дня, сделан вывод, что код подтверждения, написанный вами, является причиной, по которойне откатится, в основном по следующим трем причинам:

  1. Не согласно тому, что я сказал в начале заголовка, использование механизма хранения InnoDB, использование MyISAM, не поддерживает транзакции, естественно, не будет воспроизводиться.
  2. Это бесполезно.Согласно тому, что я сказал в начале заголовка, используются аннотации проверки JPA и JSR 303, например: MyBaits используется, поэтому, естественно, это не повторится.
  3. Функция, определяющая транзакцию, не является общедоступным типом, это базовое использование неверно, и сама транзакция не вступает в силу.

Вот несколько причин, по которым возникают эти вопросы:нет обзораа такжеОсновы транзакцийВызвано отсутствием контроля. Некоторые общие моменты, которые следует отметить в отношении базового использования транзакций."Почему добавлена ​​аннотация @Transactional, транзакция не откатывается? 》

Зачем писать поймать и откатить?

Давайте сначала посмотрим на исключение, о котором сообщается во время выполнения:

javax.validation.ConstraintViolationException: Validation failed for classes [com.didispace.chapter310.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
	ConstraintViolationImpl{interpolatedMessage='个数必须在0和5之间', propertyPath=name, rootBeanClass=class com.didispace.chapter310.User, messageTemplate='{javax.validation.constraints.Size.message}'}
]
	at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:209) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:83) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
	at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]

Это исключение является ключом к этому откату. это исключениеjavax.validation.ConstraintViolationExceptionГде это находится? Помните JSR 303, о котором я говорил раньше? Да, это исключение в Bean Validation.

Некоторые читатели говорят, что это неRuntimeException, поэтому он не будет откатываться. Очевидно, что ни одно из этих суждений на самом деле не пробовал.Пока вы открываете исходный код, вы можете сразу узнать, что эта аномалия принадлежитRunTimeExceptionиз.

На самом деле причина отката напрямую связана с использованием здесь Spring Data JPA и Hibernate Validator. Начиная с JPA 2.0 реализация этих проверок компонентов поддерживается по умолчанию, что обеспечиваетpre-persist, pre-update,pre-removeФункция проверки выполняется при возникновении трех событий. И в верификации, когда верификация не удалась, кинутьjavax.validation.ConstraintViolationException, текущая транзакция помечается какrollback.

Анализ исходного кода

Чтобы понять, что здесь происходит, лучше всего отследить исходный код. Итак, с чего начинается исходный код? Найдите подсказки в журнале исключений.

Найдите самую последнюю ошибку в стеке исключений и щелкните ее.

Количество строк с ошибкой находится в строке 532.tx.commit(), привычно добавляйте точки останова, чтобы при следующем заходе можно было видеть различные параметры в текущей ситуации.

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

Выполните программу, вызовите test4, выполните до строки 532, а затем перейдите к следующему шагу, чтобы увидеть, куда она пойдет?

В это время он войдетorg.hibernate.engine.transaction.internal.TransactionImpl, конкретное расположение выглядит следующим образом:

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

Продолжайте выполнять шаги, описанные выше, чтобы попробовать, и вы можете прийти к положению, показанному ниже:

Видно, что исключение проверки исходит из строки 271. Объединяя строки 278 и 280, понятно, почему здесь откат?

Практика приносит истинные знания, когда вы запутались, лучше писать и корректировать, и многие ответы появятся сами собой!

Если вы недостаточно понимаете, что test4 будет откатываться, или у вас есть другие читатели, у которых выполнение транзакции не соответствует ожидаемому, то следуйте моим идеям и попробуйте шаг за шагом.Вы можете наблюдать более глубоко, и ваше понимание этой части по логике будет лучше. Мы строим качественноГруппа весеннего технического обмена, разработчики, которые любят технологии, могут присоединиться к обсуждению. У каждого здесь есть свои светлые точки, учимся друг у друга, учимся друг у друга, и долго упорствуем, надеюсь, каждый станет лучшим в своей области!

Приглашаю обратить внимание на мой публичный номер: Программист ДД, поделитесь галантереей и мыслями, которых не видно снаружи!