Вы должны иметь дело с транзакцией в осторожной манере.

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

Дублирующая транзакция — это состояние, при котором транзакция создается в базе данных более одного раза, в то время как она должна быть создана один раз. Это может быть вызвано многими причинами: ошибкой в ​​​​другой системе, вызывающей дублирующий запрос к нашей системе, или когда мы не запрещаем пользователям нажимать кнопку «Сохранить», когда фоновый процесс не был выполнен.

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

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

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

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

Поэтому нам нужно создать собственное решение.

Поняв принцип Cacheablein Spring, мы можем реализовать собственную версию кэширования процессов.

Spring предоставляет нам мощный инструмент для интерференции вызовов методов, он называется Spring AOP. Spring AOP (аспектно-ориентированное программирование) может обернуть объект службы прокси-сервером и помешать этому методу службы.

Вместо прямого вызова TargetService он вызывает прокси. Внутри мы можем проверить, был ли этот вызов выполнен ранее, на основе значения параметра. Если процесс не был создан, мы сохраняем информацию о вызове в кэше, а затем продолжаем вызов метода. Делая это вместо того, чтобы ждать завершения метода, мы можем сразу сохранить информацию.

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

  1. @CachedProcess аннотировать метод информацией об имени процесса (processName) и уникальном ключе о процессе (attribute).
  2. @ProcessKey аннотируйте параметр, где мы можем найти идентификатор процесса.

Тогда это вопрос связи между аннотированными методами и нашим аспектом. Мы используем PointCut, чтобы указать, какому методу будет мешать наш Aspect:

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

Чао.