2012-06-22 3 views
3

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

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

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

+2

см. Транзакции, оптимистичная/пессимистическая блокировка и т. Д. – biziclop

ответ

6

Родной 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 будет работать таким же образом.

+0

Innodb поддерживает блокировку уровня строки, myisam - нет. У Myisam есть * одновременные * вставки, но это не одно и то же. См. [Запись 9 здесь] (https://en.wikipedia.org/wiki/Comparison_of_MySQL_database_engines). –

+0

@SpencerRathbun, ты хотел опубликовать этот комментарий к моему сообщению? Как это уместно? –

+0

Вы указываете, что проблема «UPDATE» возникла бы из-за блокировки всех строк в InnoDB, что неверно, поскольку InnoDB не блокирует всю таблицу, а только записи для обновления. –

0

попробовать с «блокировки таблицы» команду, я использовал 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) 

enter image description here

enter image description here

Смежные вопросы