2017-02-10 8 views
1

Все,Как решить проблему параллелизма?

Я использую MySql 5.7 в своем приложении. Я пытаюсь сделать мою функцию безопасности Concurrency Safe. Я объясню пример.

Пример: У меня есть два администратора Admin 1 и Admin 2. У нас есть таблица продуктов, и у нас есть запись в таблице продуктов с кодом продукта «P1». Предположим, что Admin 1 и Admin 2 вошли в систему и одновременно пытаются обновить запись продукта с кодом «P1».

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

Я использую транзакцию и не изменяю уровень транзакций по умолчанию MySql (повторяемое чтение). Я пытаюсь решить эту проблему, используя «ВЫБЕРИТЕ ДЛЯ ОБНОВЛЕНИЯ» (включая условие, в котором нужно проверить с измененным временем). Это условие «где» решит проблему параллелизма для тех транзакций, которые уже совершены. Но если две транзакции начинаются в одно и то же время и первая транзакция фиксируется до таймаута блокировки, тогда, когда вторая транзакция выполняется, она перезаписывает первый.

Пожалуйста, поделитесь своими идеями

Заранее спасибо

+0

Вы можете просто сделать LOCK TABLES product WRITE' перед тем, как появится критическая секция. Не забудьте разблокировать потом. – apokryfos

+0

@apokryfos блокировка всей таблицы до конца редактирование одной записи на самом деле не является эффективным решением – Shadow

+0

Я думаю, это может быть одно из решений: использовать движок InnoDB и 'select ... for update' – Wizard

ответ

3

Ну есть на самом деле 2 вопросы здесь.

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

Итак, все, что вам нужно для СУБД.

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

UPDATE table SET col1 = 'NewValue' 
WHERE usual criteria 
    AND col1 = 'Its Original Value' 

Таким образом, это означает, что когда вы представите исходные данные из этой строки пользователю в форме, вы должны как-то вспомнить, что его первоначальное состояние было, а также захвата его новое состояние, в которое администратор изменил его.

Конечно, код PHP также должен быть написан, чтобы зафиксировать тот факт, что UPDATE не состоялся и что-то возвратить в зависимости от того, что обновление администратора не выполнено. Отображение нового значения в соответствующем столбце и уведомление о том, что обновление не удалось, поскольку кто-то еще уже изменил это поле и позволил им либо забыть об этом, либо применить их изменения поверх других обновлений администраторов.

0

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

Создать поле на вашем столе, который будет версией для этого реестра:

alter table someTable add column version not null integer default 0; 

Там не будет никакой необходимости изменять любой код вставки с этим.

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

Тогда вам понадобится создать before update trigger для вашей таблицы, который будет проверять, является ли версия текущего реестра все той же, поэтому вы обновляете, если не поднимаете ошибку. Что-то вроде:

delimiter $$ 
create trigger trg_check_version BEFORE UPDATE 
     ON yourTable 
     for each row 
    begin 
     if NEW.version != OLD.version then 
      signal sqlstate '45000' set message_text = 'Field outdated'; 
     else 
      NEW.version = NEW.version + 1; 
     end if; 
    end$$ 
delimiter; 

Затем вы обрабатываете ошибку в своем php-коде. Команда signal будет работать только на MySql 5.5 или новее. Проверьте это thread