«ДЛЯ ОБНОВЛЕНИЯ» v / s «LOCK IN SHARE MODE»: разрешить параллельным потокам читать обновленное значение «состояния» заблокированной строки

У меня есть следующий сценарий:

  • Пользователь X входит в приложение из местоположения lc1: назовите его Ulc1
  • Пользователь X (был взломан, или его друг знает его учетные данные, или он просто входит в систему из другого браузера на своей машине и т. д., вы поняли) входит в систему на в то же время из местоположения lc2: назовите его Ulc2

Я использую основной сервлет, который:
- получает соединение из пула баз данных
- устанавливает для автоматической фиксации значение false
- выполняет команду, которая проходит через уровни приложения: если все прошло успешно, установите для autocommit значение true в операторе «finally» и закрывает соединение.В противном случае, если произойдет исключение, откат ().

В моей базе данных (mysql / innoDb) у меня есть таблица "истории" со столбцами строк:
id (первичный ключ) | имя пользователя | дата | тема | заблокирован

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

Итак, вернемся к сценарию:
-> Ulc1 отправляет команду обновить свою историю из базы данных для даты «D» и темы «T».

-> Ulc2 отправляет ту же команду в обновить историю из базы данных для той же даты "D" и такой же тема "T" в точно в то же время.

Я хочу реализовать систему блокировки mysql / innoDB, которая позволит любому приходящему потоку выполнить следующую проверку:

Является ли столбец «заблокирован» для этой строки истинным или нет?

  • если истина, вернуть пользователю сообщение о том, что «он уже обновляет те же данные из другого места»
  • если не истина (т. Е. Не заблокирован): пометить его как заблокированный и обновить, затем сбросить заблокировано на ложь после завершения .

Какой из этих двух методов блокировки mysql на самом деле позволит 2-му входящему потоку прочитать «обновленное» значение заблокированного столбца, чтобы решить, какое действие wt предпринять?

Следует ли мне использовать «FOR UPDATE» или «БЛОКИРОВКА В РЕЖИМЕ SHARE» ?

Этот сценарий объясняет, чего я хочу достичь:
- поток Ulc1 прибывает первым: столбец "заблокирован" имеет значение false, установите его в значение true и продолжайте процесс обновления
- Поток Ulc2 прибывает, пока транзакция Ulc1 все еще обрабатывается, и даже несмотря на то, что строка заблокирована с помощью функций innoDb, ему не нужно ждать, но фактически считывает «новое» значение заблокированного столбца, которое является «истиной», и поэтому на самом деле не нужно ждать, пока транзакция Ulc1 зафиксируется, чтобы прочитать значение «заблокированного» столбца (в любом случае к тому времени значение этого столбца уже будет сброшено на false).

Я не очень разбираюсь в двух типах механизмов блокировки, пока я понимаю, что LOCK IN SHARE MODE позволяет другой транзакции читать заблокированную строку, а FOR UPDATE даже не позволяет читать. Но соответствует ли это чтение обновленному значению? или второй приходящий поток должен дождаться фиксации первого потока, чтобы затем прочитать значение?

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

РЕШЕНИЕ
(пример псевдокода Jdbc на основе ответа @ Darhazer )

Таблица: [id (первичный ключ) | имя пользователя | дата | тема | заблокирован]

connection.setautocommit(false);
//transaction-1
PreparedStatement ps1 = "Select locked from tableName for update where id="key" and   locked=false);
ps1.executeQuery();

//transaction 2
PreparedStatement ps2 = "Update tableName set locked=true where id="key";
ps2.executeUpdate();
connection.setautocommit(true);// here we allow other transactions threads to see the new value

connection.setautocommit(false);
//transaction 3
PreparedStatement ps3 = "Update tableName set aField="Sthg" where id="key" And date="D" and topic="T";
ps3.executeUpdate();

// reset locked to false
 PreparedStatement ps4 = "Update tableName set locked=false where id="key";
ps4.executeUpdate();

//commit
connection.setautocommit(true);
5
задан shadesco 5 June 2014 в 03:21
поделиться