Транзакция базы данных в Java с несколькими серверами приложений с использованием Spring, MyBatis и OracleDB - PullRequest
0 голосов
/ 24 октября 2018

У меня проблема при выполнении транзакции базы данных в Java с несколькими серверами приложений.

Сценарий:

Есть две таблицы.LOCKED_FILE_INFO & FILE_INFO

1: таблица FILE_INFO содержит информацию о файлах, таких как FILEID (основной), FILENAME, USERID, FILETYPE, QTY

2: таблица LOCKED_FILE_INFO содержит информацию, такую ​​как FILEID (основной)), FILENAME и TimeOfLock

3: может быть список ФАЙЛОВ или одного ФАЙЛА, который должен быть введен в таблицу FILE_INFO & LOCKED_FILE_INFO несколькими пользователями.

4: Перед созданием записи в FILE_INFOмы блокируем этот конкретный файл в LOCKED_FILE_INFO, чтобы только 1 пользователь мог заблокировать эту информацию FILE и затем ввести ее в таблицу FILE_INFO.

5: если несколько пользователей выполняют ввод для одного и того же FILE, они получат- «Информация уже заблокирована другим пользователем».

Логика:

a: Прежде чем делать запись в таблице FILE_INFO, мы проверим таблицу LOCKED_FILE_INFO, чтобы убедиться, что файл (например, file100)уже существует

b: если файл уже существует (LOCKED) - отображение - «информация уже заблокирована другим пользователем».

c: если файл не существует (НЕ БЛОКИРОВАН), введите запись в LOCK_FILE_INFO, чтобы другой пользователь не смог заблокировать файл, и только успешный пользователь может войти только в таблицу FILE_INFO.

d: Удалить заблокированный файл из таблицы LOCKED_FILE_INFO, как только мы введем в таблицу FILE_INFO

Проблема:

Когда несколько пользователей пытаются заблокировать один и тот же файл одновременнов LOCK_FILE_INFO я получаю исключение нарушения PRIMARY_KEY. Этого не происходит, когда я запускаю один сервер приложений.Это происходит только тогда, когда запущено несколько серверов приложений (не менее 5)

Существует несколько подходов, которые я пробовал: Использование синхронизации b: Использование изоляции уровня транзакций

Однако я все еще невозможность заблокировать определенный файл, когда несколько пользователей пытаются вставить в таблицу LOCKED_FILE_INFO в одно и то же время.Однако, если задержка составляет не менее 1 секунды, проблема вообще не возникает.

Буду благодарен за любые предложения.Спасибо!

1 Ответ

0 голосов
/ 24 октября 2018

Проблема возникает из-за условия гонки в логике.А именно, две одновременные транзакции, сделанные разными пользователями, могут успешно выполнить проверку на этапе a и попытаться вставить в LOCK_FILE_INFO.Очевидно, что только один успешен, а второй потерпит неудачу.

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

У вас есть несколько вариантов решения проблемы, с которой вы столкнулись.

Обработка нарушения первичного ключа

Вы можете поймать исключениеи показать сообщение, что файл уже заблокирован.В этом случае не имеет смысла проверять, существует ли запись блокировки.То есть вам не нужно выполнять шаг a.Просто вставьте запись блокировки, и если есть нарушение первичного ключа - блокировка уже есть.

Блокировка с обновлением

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

Сначала либо всегда создайте запись для файла в LOCK_FILE_INFO при создании записи в FILE_INFO, либо сохраните информацию о блокировке в FILE_INFOтаблица (timeOfLock столбца должно быть достаточно, если NULL файл не заблокирован).

Если вам нужно заблокировать, просто выполните запрос на обновление

update LOCK_FILE_INFO
set TimeOfLock = now()
where TimeOfLock is NULL
   AND FILEID = some_id

Затемвам нужно проверить, была ли запись обновлена.Количество обновленных записей возвращается каждым оператором модификации.Чтобы получить это число, просто верните int из метода вставки в mybatis mapper.Если запись была обновлена, то эта транзакция успешно получила блокировку, иначе блокировка файла не может быть получена (либо она уже заблокирована, либо файл был удален, см. Ниже).

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

Параметры, которые не работают

Синхронизация через синхронизированный

Синхронизация с использованием ключевого слова synchronized (если все сделано правильно) будет полезна только для одного случая процесса, потому что в этом случае синхронизация выполняется с использованием внутренней блокировки процесса.Если есть несколько процессов JVM, каждый из них будет иметь свою собственную блокировку, и синхронизация не будет работать должным образом.

Сериализованный уровень изоляции

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

...