mysql - блокировка строк для запроса выбора?

У меня есть таблица MySQL (таблица-A), которая содержит список уникальных идентификаторов продукта. Приложение, которое использует эту таблицу, использует несколько потоков, каждый из которых выбирает строку таблицы (самая верхнюю), использует API для получения данных о продукте и обновления его в другой таблице (таблица-B). После этого поток удаляет соответствующую строку идентификатора продукта в таблице-A и выбирает другую для работы (цикл до тех пор, пока все строки в таблице-A не будут удалены, пока таблица-B не будет обновлена).

Как предотвратить случайную работу потоков моего приложения в той же строке таблицы-A? Есть ли способ заблокировать строку из выбранных?

Пример: поток приложения 1 выбирает строку 1 из таблицы A. Захват и обновление всех связанных данных в таблицу B из API занимает от 10 до 15 секунд. Пока это происходит, поток-2 выключится и проверит таблицу-A, чтобы выбрать строку для работы. В этом случае я хочу заблокировать только строку-1, чтобы она-нить-2 не видела и не читала, а вместо этого выбирала строку-2.

2 ответа

Решение

Собственная блокировка MySQL не обеспечивает эту функциональность. Вы можете использовать столбец для выполнения ваших "замков".

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

Один поток мог бы получить строку, подобную этой:

UPDATE mytable
SET thread_owner = :my_threadID
WHERE thread_owner = 0
LIMIT 1

Затем выберите строку следующим образом (она может не вернуть ни одной строки, если не было строк, которые нужно обработать):

SELECT *
FROM mytable
WHERE thread_owner = :my_threadID

Затем обработайте его и, наконец, удалите.

Это решение будет работать как на MyISAM, так и на InnoDB.

Однако для InnoDB это может быть медленно, потому что каждый оператор UPDATE пытается заблокировать все строки, где thread_owner = 0, и если вы не уверены, что каждый раз блокируете все строки в одном и том же порядке, это может даже привести к взаимоблокировке. Таким образом, вы можете попробовать явно заблокировать всю таблицу в вашем выражении UPDATE:

LOCK TABLES mytable WRITE;
UPDATE mytable
SET thread_owner = :my_threadID
WHERE thread_owner = 0
LIMIT 1;
UNLOCK TABLES;

Таким образом, MyISAM и InnoDB будут работать одинаково.

Попробуйте с помощью команды "lock table", я использовал 2 окна, чтобы показать вам:

jcho_1> lock table t1 write;
Query OK, 0 rows affected (0.00 sec)

jcho_2> select * from t1;

jcho_2 ждут, чтобы освободить таблицу, чтобы иметь возможность читать, когда jcho_1 сделает это:

jcho_1> unlock tables;
Query OK, 0 rows affected (0.00 sec)

jcho_2 может с его запросом.

jcho_2> select * from t1;
+----------+-------------+--------------+---------------------+
| actor_id | first_name  | last_name    | last_update         |
+----------+-------------+--------------+---------------------+
|      206 | a           | b            | 0000-00-00 00:00:00 |
|       71 | ADAM        | GRANT        | 2006-02-15 04:34:33 |
|      132 | ADAM        | HOPPER       | 2006-02-15 04:34:33 |
...
|        0 | 0           | 0            | 0000-00-00 00:00:00 |
+----------+-------------+--------------+---------------------+
202 rows in set (1 min 27.67 sec)

Другие вопросы по тегам