Таблица "сторожевой пес" не была заблокирована с помощью ТАБЛИЦ БЛОКИРОВКИ в пользовательском модуле


Я создаю модуль, который должен блокировать таблицу:

db_query('LOCK TABLES {eventi_list} READ');

$is_booked = _is_booked($uid, $nid);
if (! $is_booked) {
  $is_booked = _is_booked($uid, $nid, 'eventi_waiting_list');
}

if (! $is_booked) {
  $amount = _get_free_amount($nid);
  if ($amount > 0) {
    $insert = db_query("INSERT INTO {eventi_list} (uid, nid) VALUES($uid, $nid)");
  }
  else {
    $time = time();
    $insert = db_query("INSERT INTO {eventi_waiting_list} (uid, nid, created_at) VALUES($uid, $nid, $time)");
  }
  $update = db_query("UPDATE {content_type_event} SET field_event_places_amount_value = field_event_places_amount_value - 1 WHERE nid=$nid");
}
db_query('UNLOCK TABLES');

Я получаю ошибку (4 подобных предупреждения):

Warning: Table 'watchdog' was not locked with LOCK TABLES query:
INSERT INTO watchdog (uid, type, message, variables, severity, link, location, referer, hostname, timestamp) VALUES (19, 'php', '%message in %file on line %line.', 'a:4:{s:6:"%error";s:12:"user warning";s:8:"%message";s:139:"Table eventi_waits was not locked with LOCK TABLES query: SELECT count(nid) AS count FROM eventi_waits WHERE nid=201 AND uid=19";s:5:"%file";s:95:"D:\tools\xampp\htdocs\drupal\sites\bartenders.localhost.com\modules\\custom\eventi\eventi.module";s:5:"%line";i:115;}', 3, '', 'http://bartenders.localhost.com/bartender/book/201/%3Fdestination%3D/eventi/justin-knows', 'http://bartenders.localhost.com/eventi/justin-knows', '127.0.0.1', 1303900341) in D:\tools\xampp\htdocs\drupal\includes\database.mysqli.inc on line 135

Что я могу с этим сделать, отключить отчетность по базе данных?

 2
Author: user1077, 2011-04-27

3 answers

Это не будет работать с текущим кодом. Проблема заключается не в отчетности, а в реализации блокировки.

Из ссылка на таблицы блокировки mysql

Сеанс, требующий блокировок, должен получите все необходимые блокировки в одном операторе ТАБЛИЦ БЛОКИРОВОК. Пока полученные таким образом блокировки удерживаются, сеанс может получить доступ только к заблокированным таблицам.

Вы пытаетесь получить доступ к разблокированным таблицам, удерживая замок.

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

 3
Author: Jeremy French, 2011-04-27 12:48:48

В дополнение к тому, что сказал Джереми Френч:

  • Если вы действительно хотите сделать блокировку, вам следует использовать предоставленные функции api db_lock_table()

  • Вам действительно необходимо правильно передавать аргументы в ваши запросы с заполнителями, такими как %d и %s. То, что вы делаете, небезопасно и может привести к внедрению SQL. Перечитайте документацию db_query()

 3
Author: Berdir, 2011-04-27 12:54:07

В коде используется неправильный замок. Это описание, приведенное в справочном руководстве MySQL 5.0:

СЧИТЫВАНИЕ [ЛОКАЛЬНОЙ] блокировки:

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

Несколько сеансов могут получить блокировку ЧТЕНИЯ для таблицы одновременно.

Другие сеансы могут считывать таблицу без явного получения блокировки ЧТЕНИЯ.

ЛОКАЛЬНЫЙ модификатор включает неконфликтную ВСТАВКУ инструкции (параллельные вставки) другими сеансами для выполнения во время удержания блокировки. (См. Раздел 7.7.3, "Параллельные Вставки".) Однако ЛОКАЛЬНОЕ ЧТЕНИЕ нельзя использовать, если вы собираетесь управлять базой данных с помощью процессов, внешних по отношению к серверу, пока вы удерживаете блокировку. Для таблиц InnoDB ЛОКАЛЬНОЕ ЧТЕНИЕ совпадает с ЧТЕНИЕМ в MySQL 5.0.13. (До этого ЛОКАЛЬНОЕ ЧТЕНИЕ по существу ничего не делает: оно вообще не блокирует таблицу, поэтому для таблиц InnoDB использование ЛОКАЛЬНОГО ЧТЕНИЯ не рекомендуется, потому что простой последовательный выбор чтения делает то же самое, и никакие блокировки не требуются.)

Код получает блокировку чтения, но затем он записывается в таблицу.

Чтобы заметить, что основная ошибка вызвана тем, что "список событий" не заблокирован для записи, и из того факта, что watchdog() пытается зарегистрировать запись ошибки в таблицу, которая также не была заблокирована для записи. Как сообщил Джереми Френч, код должен получить все необходимые ему замки.

Если вы посмотрите на код db_lock_table(), которая является функцией, которую Бедир правильно предлагает использовать, вы заметите, что она получает блокировку записи.

function db_lock_table($table) {
  db_query('LOCK TABLES {' . db_escape_table($table) . '} WRITE');
}
 2
Author: kiamlaluno, 2011-04-27 13:35:14