Использование аннотации @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
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose