Рубрики
Без рубрики

Транзакция в Spring Boot максимально проста

Введение Несколько дней назад мне пришлось расследовать ошибку в производстве, связанную с ошибкой… Помечено как java, база данных, программирование, веб-разработчик.

Несколько дней назад мне пришлось расследовать ошибку в производстве, связанную с транзакцией базы данных, специально определенной аннотацией @Transaction . Это звучало как отличная возможность ознакомиться с основными концепциями и, надеюсь, исправить ошибку.

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

@Autowired
private TableOneService tableOneService;

@Autowired
private TableTwoService tableTwoService;


@PostMapping("/")
@Transactional
public void save(@RequestBody Payload payload) {
  tableOneService.save(payload);
  tableTwoService.save(payload);
}

До сих пор все было хорошо, приложение вело себя так, как ожидалось.

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

  1. Добавьте какую-нибудь проверку в метод сохранения
  2. Выдаст исключение, которое будет переведено в Неверный запрос ответ клиенту.

Не чувствуйте себя виноватым, если вы рассматривали это решение, мы также сделали это и внедрили его в производство.

Вот как выглядел код сейчас. Как разработчики, мы так несправедливо гордимся.

public class TableTwoService {
  public void save(Payload paylod) {
    if (isValid(payload)) {
     // persists on database
    } else {
     // throw some exception
    }
  }
}

Через несколько дней кто-то поднял руку:

” Эй, что-то не так, нам не хватает некоторых данных в первой таблице с момента развертывания кода проверки”.

Черт, мы даже не изменили Обслуживание за первым столом ни код контроллера API, наверняка это чья-то чужая проблема.

Короче говоря, это то, что определяет поведение метода, аннотированного @Transaction :

  1. Начните транзакцию.
  2. Выполните набор манипуляций с данными и/или запросов.
  3. Если ошибки не возникает, то зафиксируйте транзакцию.
  4. Если произошла ошибка, откатите транзакцию.
@Transactional
public void save(@RequestBody Payload payload) {
  // Both operations should work for transaction commit
  // Otherwise no operation will persist
  tableOneService.save(payload);
  tableTwoService.save(payload);
}

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

Решение, которое я решил использовать, состояло в том, чтобы удалить созданное исключение и вместо этого просто зарегистрировать полученную полезную нагрузку, чтобы я мог лучше наблюдать за этим потоком. Исключение теперь не приведет к откату транзакции.

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

public class TableTwoService {
  public void save(Payload paylod) {
    if (isValid(payload)) {
     // persists on database
    } else {
     // log a message and do nothing
    }
  }
}

Теперь ошибка исправлена, и я узнал немного больше об аннотации @Transaction . Я надеюсь, что эта история поможет кому-то еще в будущем.

Оригинал: “https://dev.to/fabiothiroki/transaction-in-spring-boot-as-simple-as-possible-5ecf”