Блокировка на уровне строк — MySQL — для обновления

Я все еще не понимаю блокировку строк таблицы. Я использую MySQL/PHP, и вот мой сценарий.

У меня есть набор таблиц, которые мое приложение использует для отслеживания запросов и сообщений. Пользователь создает публикацию (таблица POSTING(P)) для элемента (таблица ITEM(I)) и может отправлять запросы отдельным пользователям (таблица REQUEST(R)) или может размещать ее и получать ответы на публикацию (таблица POSTING_RESPONSE(PR )) который будет принят пользователем, разместившим элемент.

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

Что я хочу сделать, если кто-то примет запрос:

  1. заблокировать строку в таблице ITEM (I), соответствующую элементу

  2. заблокировать строку в таблице POSTING (P) (если строка существует), соответствующую элементу

  3. заблокировать строку (строки) в таблице REQUEST (R) для любых запросов, отправленных для элемента

  4. заблокировать строку (строки) в таблице POSTING_RESPONSE (PR) (если строки существуют), соответствующие элементу

  5. обновить статус ПУНКТА на «Зарезервировано»

  6. обновить статус POSTING на «Недоступно»

  7. обновить все/любые POSTING_RESPONSE до «Отклонено»

  8. обновить все ЗАПРОСЫ до «Отклонено», кроме того, который был принят — обновить его до «Принято»

Пожалуйста, не обращайте внимания на избыточность статуса в этом примере.

Теперь я предположил, что № 1–4 можно выполнить с помощью простого «выбрать ... для обновления», оставив AUTOCOMMIT как false. С помощью этих операторов select я мог определить, следует ли мне обновляться, и если да, то я могу продолжить обновления. Затем, после завершения обновлений № 5-8, я бы зафиксировал, и строки были бы разблокированы.

У меня проблемы с тем, чтобы заставить это работать, и я не знаю, связано ли это с чем-то, что я делаю, или с тем, что я неправильно думаю.

Еще одна вещь... есть другие процессы, которые могут обновить статус элемента, скажем, на ИСТЕКШИЙ или ОТМЕНЕННЫЙ. Я надеюсь, что единственное решение моего подхода состоит не в том, чтобы поместить каждое возможное условие в предложение WHERE в операторах UPDATE... это было бы нелегко поддерживать.


person NEW2WEB    schedule 30.10.2014    source источник


Ответы (1)


Мини-транзакция: сделать это одним запросом.

UPDATE item
LEFT JOIN posting
   ON posting.item_id = item.id -- or however
LEFT JOIN request 
   ON request.item_id = item.id -- or however
LEFT JOIN posting_reponse
   ON posting_response.item_id = item.id 
SET 
   item.status = 'Reserved',
   posting.status = 'Unavailable',
   posting_reponse.status = 'Rejected',
   request.status = IF(request.id = some-current-id,'Accepted','Rejected')
WHERE item.id = some-id AND item.status='Available';

... и перестаньте задавать вопросы о блокировке для чтения, вы действительно этого не хотите :P

person Wrikken    schedule 30.10.2014
comment
Wrikken - это, вероятно, путь, но я все еще не понимаю, что не так с блокировкой для чтения? - person NEW2WEB; 30.10.2014
comment
Если вы скажете: «ни один другой процесс не может читать эти данные», они не будут игнорировать эти данные, но процессы будут зависать, пока данные не станут доступными. Хотя это работает нормально на проектах с очень низким трафиком, оно не масштабируется за пределы нескольких посетителей: любой умеренно активный проект остановится со всеми видами (под)процессов/запросов, ожидающих других. Запросы занимают все больше и больше времени по мере увеличения трафика, и вы достигаете точки, в которой возникают ошибки времени ожидания блокировки. Вы можете увеличить этот тайм-аут, но никто больше не будет использовать ваш проект, если им придется ждать › минуту, чтобы что-то произошло. - person Wrikken; 30.10.2014