Использование аннотации @Transactional и сценарии сбоя транзакции
Использование аннотации @Transactional и сценарии сбоя транзакции

1. Суть дела

1. Что такое управление транзакциями?

Транзакция базы данных — это серия операций, которые выполняются как единая логическая единица работы либо полностью, либо не выполняются вообще.

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

Чтобы логическая единица работы была транзакцией, она должна удовлетворять так называемым свойствам ACID (атомарность, согласованность, изоляция и долговечность). Транзакция — это логическая единица работы в операции с базой данных.

2. Управление транзакциями в Spring

В реальной работе мы в основном комбинируем Spring для выполнения проектов. В настоящее время нам приходится сталкиваться с такой ситуацией.

Язык кода:javascript
копировать
  Уровень контроллера:
  UserService:addUser();
  Уровень обслуживания (UserService):
   addUser(): insertUser()+ insertLog()
  Слой Дао:
   UserDao:insertUser();
   LogDao: insertDao();

Видно, что мы можем вызывать несколько методов Dao в Service для работы с данными в базе данных. Нам нужно убедиться, что соответствующие операции в методе addUser() в UserService соответствуют требованиям транзакции.

Распространенные способы запуска транзакций Spring: @Transactional

2. @Транзакционная аннотация

1. Принцип:

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

Низкоуровневая реализация:

2. Введение атрибута:

уровень изоляции @Transactional ( isolation = Isolation.DEFAULT ) : Чтобы решить проблемы, которые могут возникнуть в базе данных, используется стратегия обработки иерархической блокировки.

уровень изоляции

описывать

ISOLATION_DEFAULT

Spring 默认уровень изоляции,ксоединятьизбаза данныхизделауровень изоляции С учетом;Mysql (повторяемое чтение)

ISOLATION_READ_UNCOMMITTED

Чтение незавершенного: Минимальный уровень уровня его смысл состоит в том, чтобы позволить одному делу прочитать другое дело без предоставления данных. Незавершенное чтение представляет собой опасность изуровень изоляции,так обычно не широко используется в нашей реальной разработке середина,Но его преимущество заключается в высокой возможности параллелизма.,Подходит для сценариев, которые не требуют согласованности данных, но требуют высокого уровня параллелизма.,Его самым большим недостатком является возникновение грязных операций чтения.

ISOLATION_READ_COMMITTED

Чтение зафиксировано: означает, что транзакция может читать только данные, отправленные другой транзакцией, но не может читать незафиксированные данные.

ISOLATION_REPEATABLE_READ

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

ISOLATION_SERIALIZABLE

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

Время ожидания (@Transactional (timeout = 30)): определите, сколько времени будет продолжаться процесс выполнения транзакции, чтобы его можно было откатить после истечения времени ожидания. Это может предотвратить занятие ресурсов длительными транзакциями. Соответствует тайм-ауту атрибута в аннотации (примечание: этот тайм-аут находится в пределах тайм-аута транзакции базы данных).

Доступна ли она только для чтения (@Transactional (readOnly = true)): указывает, что эта транзакция только считывает данные, но не обновляет данные.

Механизм отката (@Transactional (rollbackFor = Exception.class): определите стратегию отката при возникновении исключения.

Механизм распространения (@Transactional (propagation = Propagation.REQUIRED): определяет характеристики распространения транзакции, всего существует 7 типов (одна транзакция вызывает другую транзакцию)

транзакционное поведение

иллюстрировать

PROPAGATION_REQUIRED

Если транзакция существует в текущем контексте, присоединитесь к транзакции. Если транзакции нет, создайте транзакцию. Это значение атрибута распространения по умолчанию.

PROPAGATION_SUPPORTS

Если транзакция существует в текущем контексте, поддерживается присоединение к транзакции. Если транзакции нет, для ее выполнения используется нетранзакционный метод.

PROPAGATION_MANDATORY

Поддерживает текущие транзакции. Если текущей транзакции нет, будет выдано исключение.

PROPAGATION_REQUIRES_NEW

Каждый раз будет создаваться новая транзакция, и транзакция в контексте будет приостанавливаться. После завершения выполнения текущей новой транзакции контекстная транзакция будет возобновлена ​​и выполнена снова.

PROPAGATION_NOT_SUPPORTED

Если транзакция существует в текущем контексте, текущая транзакция приостанавливается, а затем новый метод выполняется в среде без транзакции.

PROPAGATION_NEVER

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

PROPAGATION_NESTED

Если транзакция в настоящий момент существует, она выполняется внутри вложенной транзакции. Если текущей транзакции нет, выполните операции, аналогичные PROPAGATION_REQUIRED.

3. Распространенные сценарии аннотаций @Transactional, в которых транзакция не вступает в силу

1. Проблемы с правами доступа (вступят в силу только общедоступные методы)

Пример кода:

Язык кода:javascript
копировать
@Service
public class UserService {
  @Transactional
  private void add(UserModel userModel) {
    saveData(userModel);
    updateData(userModel);
  }
}

Причина: Spring требует, чтобы прокси-метод был общедоступным.

Другими словами, если наш пользовательский метод транзакции (т. е. целевой метод) имеет права доступа, отличные от общедоступных, но закрытые, по умолчанию или защищенные, Spring не будет предоставлять функции транзакций.

2. Если метод изменен с помощью Final, он не вступит в силу.

Пример кода:

Язык кода:javascript
копировать
@Service
public class UserService {
  @Transactional
  public final void add(UserModel userModel){
    saveData(userModel);
    updateData(userModel);
  }
}

причина:

Нижний уровень транзакций Spring использует AOP, то есть через динамический прокси JDK или CGLIB он помогает нам генерировать прокси-классы и реализовывать функции транзакций в прокси-классах. Но если метод изменен с помощью Final, то в его прокси-классе метод не может быть переопределен и добавлена ​​функция транзакции.

Примечание. Если метод статически изменен, его нельзя превратить в метод транзакции через динамический прокси.

3. Прямые вызовы внутри одного и того же метода приведут к сбою транзакции.

Пример кода:

Язык кода:javascript
копировать
@Service
public class UserService {
  @Autowired
  private UserMapper userMapper;
  
  public void add(UserModel userModel) {
    userMapper.insertUser(userModel);
    updateStatus(userModel);
  }

  @Transactional
  public void updateStatus(UserModel userModel) {
    doSameThing();
  }
}

причина:

Мы видим, что в методе транзакции add напрямую вызывается метод транзакции updateStatus. Из предыдущего введения мы знаем, что метод updateStatus имеет возможности транзакций, поскольку Spring AOP генерирует прокси-объекты. Однако этот метод напрямую вызывает метод этого объекта и не получает динамику методов, связанных с транзакциями AOP, от прокси-объекта. поэтому метод updateStatus не генерирует транзакцию

4. (Сам класс) не управляется Spring.

Пример кода:

Язык кода:javascript
копировать
//@Service
public class UserService {

  @Transactional
  public void add(UserModel userModel) {
    saveData(userModel);
    updateData(userModel);
  }    
}

причина:

Предварительным условием для использования транзакций Spring является то, что если объектом будет управлять Spring IOC, необходимо создать экземпляр компонента.

5. Многопоточные вызовы

Пример кода:

Язык кода:javascript
копировать
@Service
public class UserService {

  @Autowired
  private UserMapper userMapper;
  @Autowired
  private RoleService roleService;

  @Transactional
  public void add(UserModel userModel) throws Exception {
    userMapper.insertUser(userModel);
      new Thread(() -> {
        roleService.doOtherThing();
      }).start();
  }
}

@Service
public class RoleService {
  @Transactional
  public void doOtherThing() {
  }
}

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

6. Характеристики распространения ошибок

Пример кода:

Язык кода:javascript
копировать
@Service
public class UserService {
  @Autowired
  private UserMapper userMapper;
  @Autowired
  private RoleService roleService;
  
  @Transactional(propagation = Propagation.REQUIRED)
  public void add(UserModel userModel) throws Exception {
    userMapper.insertUser(userModel);
      new Thread(() -> {
        roleService.doOtherThing();
      }).start();
  }
}

@Service
public class RoleService {
  @Transactional(propagation = Propagation.NEVER)
  public void doOtherThing() {
  }
}

причина:RoleService середина doOtherThing() Тип распространения транзакции, установленный для метода: Propagation.NEVER, выдает исключение, если есть транзакция.

7. Я проглотил что-то ненормальное

Пример кода:

Язык кода:javascript
копировать
@Slf4j
@Service
public class UserService {
  @Transactional
  public void add(UserModel userModel) {
    try {
      saveData(userModel);
      updateData(userModel);
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }
}

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

8. Если диспетчер транзакций не может обработать возникшее исключение, его откат не будет выполнен.

Пример кода:

Язык кода:javascript
копировать
@Slf4j
@Service
public class UserService {
  @Transactional
  public void add(UserModel userModel) throws Exception {
    saveData(userModel);
    updateData(userModel);
  }
}

причина:@Transactional Тип исключения по умолчанию: RuntimeException, если не RuntimeException, Spring Если транзакция не может обработать соответствующее исключение и программа считается нормальной, транзакция не будет отменена. На этом этапе мы можем указать тип исключения, например. @Transactional(rollbackFor = Exception.class)

9. Ядро базы данных не поддерживает транзакции.

например Mysql серединаиз MyISAM Движок не поддерживает операции транзакций. InnoDB Это механизм, который поддерживает транзакции

4. Резюме:

В этой статье представлена ​​аннотация @Transactional и перечислены сценарии, в которых может произойти сбой транзакции. Три наиболее распространенных случая — это самовызов, перехват исключения и несоответствие типа выдачи исключения. Из-за большой рабочей нагрузки иногда игнорируются спецификации использования аннотации @Transactional, в результате чего транзакция не вступает в силу или откатывается обычным образом, что приводит к большим аномалиям данных.

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода