предисловие
-
Декларативная транзакция — одна из самых крутых функций Spring, но иногда мы используем декларативную транзакцию, и она не вступает в силу, почему?
-
Сегодня Чен взял вас, чтобы рассказать о нескольких неудачных сценариях постановления дел. В этой статье мы обсудим, почему транзакции терпят неудачу из-за следующих двух аспектов?
-
Введение в @Transactional
-
@Сценарии аннулирования транзакций
-
Введение в @Transactional
-
`@Transactional` — это декларативная аннотация транзакции, которая может быть помечена на `класс`, `интерфейс`, `метод`.
-
В этой аннотации есть несколько свойств, которые стоит подробно изучить, давайте посмотрим.
transactionManager
-
Указывает менеджер транзакций. Значением является имя компонента. В основном используется в случае нескольких менеджеров транзакций. Например, в случае нескольких конфигураций источников данных.
isolation
-
Уровень изоляции транзакции, по умолчанию `Isolation.DEFAULT`.
-
Значения нескольких значений следующие:
-
`Isolation.DEFAULT`: уровень изоляции транзакции по умолчанию, использующий уровень изоляции базы данных по умолчанию.
-
`Isolation.READ_UNCOMMITTED`: это самый низкий уровень изоляции транзакции, который позволяет другой транзакции видеть незафиксированные данные этой транзакции. Этот уровень изоляции производит грязные чтения, неповторяемые чтения и фантомные чтения.
-
`Isolation.READ_COMMITTED`: убедитесь, что данные, измененные одной транзакцией, могут быть прочитаны другой транзакцией только после ее фиксации. Другая транзакция не может прочитать незафиксированные данные транзакции. Этот уровень изоляции транзакций позволяет избежать грязных чтений, но может иметь место неповторяющееся чтение и фантомное чтение.
-
`Isolation.REPEATABLE_READ`: этот уровень изоляции транзакций предотвращает грязное чтение, неповторяющееся чтение. Но могут возникать фантомные чтения.
-
`Isolation.SERIALIZABLE`: это самый дорогой, но самый надежный уровень изоляции транзакций. Транзакции обрабатываются для последовательного выполнения. Помимо предотвращения грязных и неповторяемых чтений, он также позволяет избежать фантомных чтений.
-
propagation
-
Представляет поведение распространения транзакции, значение по умолчанию — «Propagation.REQUIRED».
-
`Propagation.REQUIRED`: если транзакция существует, текущая транзакция поддерживается. Если транзакции нет, запустите новую транзакцию. Например, если метод A вызывает метод B внутренне, метод B будет использовать транзакцию метода A.
-
`Propagation.MANDATORY`: Поддерживает текущую транзакцию, генерирует исключение, если текущей транзакции нет.
-
`Propagation.NEVER`: Выполняется нетранзакционным способом, вызывая исключение, если в данный момент есть транзакция.
-
`Propagation.NOT_SUPPORTED`: выполнить операцию без транзакций. Если есть текущая транзакция, приостановить текущую транзакцию.
-
`Propagation.REQUIRES_NEW`: создать новую транзакцию. Если есть текущая транзакция, приостановить текущую транзакцию. Например, метод A использует атрибут распространения транзакции по умолчанию, а метод B использует REQUIRES_NEW. В настоящее время метод A внутренне вызывает метод B. В случае сбоя метода A транзакция в методе A откатывается, а метод B — нет. , Поскольку методы A и B не используют одну и ту же транзакцию, метод B создает новую транзакцию.
-
`Propagation.NESTED`: поддерживает текущую транзакцию и добавляет точку сохранения, то есть перед входом в подтранзакцию родительская транзакция устанавливает точку отката, которая фиксируется или откатывается синхронно с текущей транзакцией. Дочерняя транзакция является частью родительской транзакции, и дочерняя транзакция не должна быть зафиксирована, если родительская транзакция не была зафиксирована. Очень важная концепция вложенных транзакций заключается в том, что внутренняя транзакция зависит от внешней транзакции. Когда внешняя транзакция терпит неудачу, действия, выполненные внутренней транзакцией, откатываются. Сбой операции внутренней транзакции не приведет к откату внешней транзакции.
timeout
-
Время ожидания транзакции, в секундах.
readOnly
-
Это свойство используется, чтобы указать, является ли текущая транзакция транзакцией только для чтения. Если установлено значение true, оно означает, что оно доступно только для чтения, а false означает, что транзакция может быть прочитана и записана. Значение по умолчанию — false. Может быть установлено значение true, если транзакция включает только чтение.
откатДля свойства
-
Используется для указания типа исключения, которое может инициировать откат транзакции.Можно указать несколько типов исключений.
-
По умолчанию выполняется откат при RuntimeException и Error.
noRollbackFor
-
Генерирует указанный тип исключения и не откатывает транзакцию.Также можно указать несколько типов исключений.
@Сценарии аннулирования транзакций
-
Существует множество сценариев сбоя декларативных транзакций. Здесь Чен перечисляет лишь несколько распространенных сценариев.
Базовый механизм базы данных не поддерживает транзакции
-
Если ядро базы данных не поддерживает транзакции, Spring, естественно, не может поддерживать транзакции.
Использование в непубличных модифицированных методах
-
В аннотации @Transactional используется АОП. При использовании динамического прокси-сервера он может проксировать только метод "public". Исходный код основан на методе "computeTransactionAttribute" в классе "AbstractFallbackTransactionAttributeSource":
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; }
-
Если он не помечен в модифицированном методе `public`, он не вызовет исключение, но приведет к сбою транзакции.
Аномалию «забили насмерть»
-
В этом случае Xiaobai наиболее склонен к ошибкам.Использование try-catch в методе всей транзакции приведет к тому, что исключение не будет выброшено, что, естественно, приведет к сбою транзакции. Псевдокод выглядит следующим образом:
@транзакционный публичный недействительный метод () { пытаться{ //вставляем часть данных //изменить часть данных }поймать(Исключение ex){ возвращение; } }
метод, вызывающий аналогичный метод
-
Проще говоря, «метод A» в классе (не отмеченный декларативной транзакцией) внутренне вызывает «метод B» (с отмеченной декларативной транзакцией), что приведет к сбою транзакции в методе B.
-
код показывает, как показано ниже:
тест открытого класса { публичная пустота A () { //вставляем часть данных // вызов метода Б Б(); }
@транзакционный публичная пустота B () { //вставляем данные } }
-
**Почему это не удается? **: На самом деле причина очень проста. Spring будет автоматически генерировать прокси-класс (proxy) для класса, отмеченного аннотацией `@Transactional`, при сканировании bean-компонентов. класс прокси. , класс прокси откроет транзакцию и выполнит операцию транзакции перед вызовом, но методы в одном классе вызывают друг друга, что эквивалентно `this.B()`. В это время метод B вызывается не прокси-классом, а напрямую через исходный. Некоторые bean-компоненты вызываются напрямую, поэтому аннотация будет недействительной.
-
** Как это решить? **: Это связано с причинами отказа аннотаций, которые будут представлены в последующих статьях, но здесь я не буду вводить слишком много.
Свойство rollbackFor задано неправильно
-
Нетрудно понять, что указанное исключение вызывает откат: если настройка неверна, некоторые исключения не могут вызвать откат, а декларативная транзакция в это время недействительна.
Свойство noRollbackFor задано неправильно
-
Это похоже на ошибку установки свойства rollbackFor.Если установка неверна, исключение не вызовет откат, и декларативная транзакция в это время будет недействительной.
Свойство распространения задано неправильно
-
Свойства распространения транзакций были представлены выше. Свойство распространения транзакции по умолчанию – "Propagation.REQUIRED", но если будет настроено неправильное свойство распространения, это также приведет к сбою транзакции. Следующие три конфигурации приведут к сбою транзакции. :
-
Propagation.SUPPORTS
-
Propagation.NOT_SUPPORTED
-
Propagation.NEVER
-
Исходный проект SSM, повторное сканирование приводит к аннулированию транзакции
-
В исходном проекте SSM настраивается `context:component-scan`, и уровень службы сканируется одновременно, и транзакция будет недействительной.
-
В соответствии с порядком загрузки файла конфигурации Spring файл конфигурации Springmvc будет загружен первым.Если служба также загружается при загрузке файла конфигурации Springmvc, но транзакция в это время не загружена, транзакция не будет выполнена. успешно подействовать.
-
Решение очень простое, просто установите конфигурацию слоя службы сканирования в файле конфигурации Spring или других файлах конфигурации.
Суммировать
-
Причин провала дел много, но не будьте наполовину понятыми, только когда у вас есть глубокое понимание, вы сможете гладко ответить на них в процессе собеседования.
-
**На этом сегодняшняя статья подходит к концу.Если вы считаете, что Чен написал хорошо и что-то понял, обратите на это внимание.Друзья приглашаем обратить внимание на публичный аккаунт Чена! ! ! **
-