@Transactional откат исключений по умолчанию и поведение распространения транзакций
Это очень удобно, когда мы используем Spring для управления транзакциями базы данных, нам нужно только ввести аннотации в прокси-объект@Transactional
Бизнес можно начинать. мы используем@Transactional
Общие касаются двух основных аспектов, один из которых — определение аномального отката (установкаrollbackFor
), другая - определение поведения распространения транзакции (настройкаpropagation
).
По умолчанию, когдаRuntimeException
иError
будет откатываться. По умолчанию распространение транзакции поддерживает текущую транзакцию и создает новую транзакцию, если транзакция не существует. Приведенное выше поведение по умолчанию может охватывать большую часть сценариев приложений, что очень удобно в использовании, и может быть адаптировано к большей части сценариев приложений без настройки параметров. Но когда более двух служб используют транзакции, вам нужно больше знать о поведении распространения транзакций.
Поведение распространения транзакций, определенное в Spring
веснойorg.springframework.transaction.TransactionDefinition
Поведение распространения транзакции определено в , всего существует 7 вариантов поведения, которые можно разделить на три категории в зависимости от того, поддерживается текущая транзакция или нет.
- Поддержать текущую транзакцию
-
PROPAGATION_REQUIRED
: Если транзакция уже существует, используйте эту транзакцию. Если текущей транзакции нет, создайте новую транзакцию. -
PROPAGATION_SUPPORTS
: если в данный момент есть транзакция, используйте эту транзакцию, если текущей транзакции нет, по-прежнему запускайте ее без транзакций. -
PROPAGATION_MANDATORY
: если есть текущая транзакция, использовать транзакцию, если текущая транзакция не существует, создать исключение
-
- Текущая транзакция не поддерживается
-
PROPAGATION_REQUIRES_NEW
: Всегда создайте новую транзакцию, если транзакция в настоящее время текущая подвеска транзакции -
PROPAGATION_NOT_SUPPORTED
: запустить в нетранзакционном режиме, если есть текущая транзакция, приостановить текущую транзакцию -
PROPAGATION_NEVER
: работать в транзакционном режиме, выдавать исключение, если в данный момент есть транзакция
-
- вложенные транзакции
-
PROPAGATION_NESTED
: в настоящее время существует транзакция, создайте вложенную транзакцию для запуска, если текущей транзакции нет, поведение эквивалентноPROPAGATION_REQUIRED
-
Выше приведено описание 7 видов поведения распространения транзакций.Простое описание здесь будет абстрактным и непростым для понимания.Описаны следующие три общих поведения распространения транзакций.REQUIRED ,REQUIRED_NEW ,NESTED
Портфолио услуг продемонстрировано и объяснено.
Пример использования стандартного поведения при распространении транзакций
1 Восходящая служба ТРЕБУЕТСЯ, а нисходящая служба не добавляет транзакций
восходящий сервис
@Transactional(rollbackFor = Exception.class)
public void createUser() {
User user = new User();
user.setAge(19).setName("test1").setVersion(1);
userMapper.insert(user);
logService.saveLog("createUser");
}
Нисходящий сервис выдает исключение:
public void saveLog(String method) {
SystemLog entity = new SystemLog();
entity.setMethod(method);
systemLogMapper.insert(entity);
throw new RuntimeException("测试回滚 saveLog未添加事务,createUser Propagation.REQUIRED");
}
Затем текущая транзакция вступает в силу, и текущая службаcreateUser
и последующие услугиsaveLog
Откатится назад.
2 Текущий сервис REQUIRED, нисходящий сервис REQUIRES_NEW
2.1 Нисходящий сервис выдает исключение
Код вышестоящей службы остается неизменным, а код нижестоящей службы модифицируется следующим образом.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(String method) {
SystemLog entity = new SystemLog();
entity.setMethod(method);
systemLogMapper.insert(entity);
throw new RuntimeException("测试回滚 saveLog Propagation.REQUIRES_NEW,createUser Propagation.REQUIRED");
}
Затем текущая транзакция вступает в силу, и текущая службаcreateUser
и последующие услугиsaveLog
будет откатываться. Транзакция текущей службы приостанавливается, нисходящая транзакция откатывается, и исключение также вызывает откат восходящей транзакции. Так что все равно откатится.
2.2 Исключения, выбрасывающие сервис восходящего потока
Поместите операцию, которая выдает исключение в вышестоящую службу, а нижестоящая служба вернется к нормальной логике.Измененный код выглядит следующим образом
@Transactional
public void createUser() {
User user = new User();
user.setAge(19).setName("test1").setVersion(1);
userMapper.insert(user);
logService.saveLog("createUser");
throw new RuntimeException("上游服务createUser Propagation.REQUIRED 抛出异常 " +
"下游服务saveLog REQUIRES_NEW");
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(String method) {
SystemLog entity = new SystemLog();
entity.setMethod(method);
systemLogMapper.insert(entity);
}
восходящий сервисcreateUser
Откат, новые данные не вставляются в t_user, нижестоящие сервисыsaveLog
Успешное выполнение В t_system_log записывается новая порция данных. Причина в том, что нисходящая транзакция настроена какREQUIRES_NEW
Когда выполняется нижестоящий сервисный код, текущая транзакция приостанавливается, нижестоящая транзакция выполняется, нижестоящая транзакция выполняется без исключений, выполняется плавно и возвращается в вышестоящую транзакцию. происходит откат вверх по течению.
использование нисходящей транзакцииREQUIRES_NEW
Вверх по течению и нисходящими являются двумя изолированными транзакциями, сбой не повлияет на нижний по течению, представленные непосредственно до восходящего бизнеса, если только он не является первым случаем, в режиме ожидания будет бросается исключение, которое будет брошено в службу вверх по течению. Отказ
3 Используйте REQUIRES_NEST
Существует два требования к сценариям с использованием вложенных транзакций:
- Совместный успех: восходящая транзакция должна быть зафиксирована вместе с нижестоящей транзакцией, то есть: нижестоящая транзакция фиксируется только тогда, когда восходящая транзакция успешно зафиксирована. с этой точки зрения
PROPAGATION_REQUIRED
сможет сделать. - Сбой изоляции: необходимо откатить нижестоящую транзакцию, не влияя на фиксацию вышестоящей транзакции. Это требование называется просто «отказ изоляции». с этой точки зрения
PROPAGATION_REQUIRES_NEW
сможет сделать.
При использованииPROPAGATION_REQUIRED
Требование 1 соответствует, но откат транзакции ниже по течению будет безоговорочно, приведет к возврату репутации вверх по течению, что не может соответствовать требованию 2. Неспособность транзакции ниже по течению к фиксированию не влияет на допущенную транзакцию.
использоватьPROPAGATION_REQUIRES_NEW
Требование 2 выполнено, но нижестоящая транзакция представляет собой совершенно новый контекст транзакции, и успешная отправка восходящей транзакции никак не влияет на нижестоящую отправку, которая не может удовлетворить требованию 1.
Нужно использоватьNESTED
Только когда восходящий поток влияет на нисходящий поток, нисходящий поток не влияет на восходящий поток.
Пример кода:
3.1 Восходящая служба использует механизм PROPAGATION_REQUIRED для создания исключения, а нижестоящая служба использует механизм NESTED.
上游服务
@Transactional
public void createUser() {
User user = new User();
user.setAge(19).setName("test1").setVersion(5);
userMapper.insert(user);
logService.saveLog("createUser");
throw new RuntimeException("上游抛出异常,下游NESTED机制");
}
下游服务
@Transactional(propagation = Propagation.NESTED)
public void saveLog(String method) {
SystemLog entity = new SystemLog();
entity.setMethod(method);
systemLogMapper.insert(entity);
}
Отказ от вверх по течению и ниже по течению будет возвращен.
3.2 Служба вверх по течению использует механизм пропаганды_распределения, а сервис вниз по течению использует вложенный механизм для броска исключений
上游服务
@Transactional
public void createUser() {
User user = new User();
user.setAge(19).setName("test1").setVersion(5);
userMapper.insert(user);
try {
logService.saveLog("createUser");
}catch (Exception e) {
}
}
下游服务
@Transactional(propagation = Propagation.NESTED)
public void saveLog(String method) {
SystemLog entity = new SystemLog();
entity.setMethod(method);
systemLogMapper.insert(entity);
throw new RuntimeException("下游使用NESTED机制抛出异常");
}
Восходящая фиксация выполняется нормально, а откат нисходящей не влияет на фиксацию восходящей.
Суммировать
Вот семь способов распространения транзакций Spring, которые разделены на три категории, поддерживающие текущие транзакции:PROPAGATION_REQUIRED,PROPAGATION_SUPPORTS,PROPAGATION_MANDATORY
Текущая транзакция не поддерживается:PROPAGATION_REQUIRES_NEW,PROPAGATION_NOT_SUPPORTED,PROPAGATION_NEVER
и вложенные транзакции:NESTED
.
Три наиболее часто используются подробно описаныPROPAGATION_REQUIRE PROPAGATION_REQUIRES_NEW NESTED
распространять поведение