Master-X
Форум | Новости | Статьи
Главная » Форум » Программинг, Скрипты, Софт, Сервисы » 
Тема: InnoDB. блокировка строки на чтение
цитата
31/03/11 в 19:29
 FXIX
Товарищи как строку на чтение заблокировать? Скрипт выбирает строку из базы. ее локает. потом разлокает.

типа:
select * from table where id=1
далее лок (чтобы второй такой же скрипт не смог прочитать эту строку).
далее разлок.

как быть?

Нашел такое:
Создать БД "TEST"
mysql -u root
use TEST;
CREATE TABLE t (a INT KEY) ENGINE = InnoDB;
INSERT INTO t VALUES (1), (2);

1. клиент
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT * FROM t WHERE a=1 FOR UPDATE;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)


2. клиент
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT * FROM t WHERE a=1 FOR UPDATE;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Ну и пока в первом клиенте "COMMIT;" не сделать, то второй клиент не может прочитать строку.

Усложним запрос. Выборка рандомно одного из значений(в обоих клиентах):
SELECT * FROM t ORDER BY RAND() LIMIT 1 FOR UPDATE;
По идее одно из значений выбирается, второе значение по идее должно выбираться во втором клиенте. но результат тот же.

Или я не тем путем иду?
цитата
31/03/11 в 21:00
 Sterx
а вот если гипотетически скрипт в процессе прервет выполнение. строка так и останется локнутой?
цитата
31/03/11 в 21:32
 FXIX
разлочит
цитата
31/03/11 в 21:40
 Stek
http://dev.mysql.com/doc/refman/5.0/en/innodb-lock-modes.html
оно ?
Или чего ты хочешь добиться в результате ? При старте транзакции данные лочатся вроде сами по умолчанию.
цитата
31/03/11 в 21:58
 FXIX
ну хочу выбрать селектом строку. ее залочить. чтобы другой экземпляр скрипта эту же строку не выбрал.

крон:
*/5 * * * * php script1.php
*/5 * * * * php script2.php

база:
10 строк в таблице

script1.php:
берет рандомно одну строку.
лочит.
с ней работает.
разлочивает.

script1.php:
берет рандомно одну строку. (не должен взять залоченную первым скриптом).
лочит.
с ней работает.
разлочивает.

за линк спасибо. курю
цитата
31/03/11 в 23:42
 CABMIT
Так а при чём тут это? Лок строки не помешает второму клиенту выбрать ту же самую строку, он просто будет ждать освобождения лока. Тут надо действовать по-другому. Например, в каком-нибудь файле или даже в бд записать id выбранной первым скриптом строки, а во втором сделать условие (SELECT ... WHERE id != ид_выбранное_первым_скриптом). Как-то так, если я правильно понял задачу
цитата
01/04/11 в 11:31
 FXIX
CABMIT писал:
Тут надо действовать по-другому. Например, в каком-нибудь файле или даже в бд записать id выбранной первым скриптом строки, а во втором сделать условие (SELECT ... WHERE id != ид_выбранное_первым_скриптом). Как-то так, если я правильно понял задачу

ну это самый простой вариант. добавить в таблицу поле
`lock` ENUM('0','1') NOT NULL DEFAULT '0' COMMENT '1-лок, 0-разлок'
и при выборке строки - сразу эту же строку апдейтить и ставить lock=1. а потом снова апдейтить и снимать. Хотел на базу повесить геморой этот. Но видимо не получиться.

Для варианта:
1. клиент
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT a FROM t WHERE a=1 FOR UPDATE;

2. клиент
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT a FROM t WHERE a=2 FOR UPDATE;

все прекрасно работает. второй клиент не прочитает строку a=1.

Но, уже для такого запроса:
SELECT a FROM t ORDER BY RAND() LIMIT 1 FOR UPDATE;
уже не работает.

И даже для такого:
SELECT * FROM t WHERE a=(SELECT a FROM t ORDER BY RAND() LIMIT 1) FOR UPDATE;

Т.е. надо рандомно выбрать 1 строку. и ее локнуть. Видимо внутреннее устройство таково что сначала выбираются все строки, а потом из них выбирается одна. Последним селектом вот я одну строку выбрал. и локнулись все сразу
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
цитата
01/04/11 в 12:28
 Sterx
неужели нельзя тупо помечать произвольный флаг в записи. транзакции блин юзать. простота залог здоровья
цитата
01/04/11 в 12:53
 taj
а так не пройдёт чтоли?
Код:
SELECT * FROM t WHERE id=(SELECT id FROM t WHERE lockFiled=0 ORDER BY RAND() LIMIT 1) FOR UPDATE;
цитата
01/04/11 в 22:20
 FXIX
taj: да это понятно. с локом то. Запрос
SELECT * FROM t WHERE a=(SELECT a FROM t ORDER BY RAND() LIMIT 1) FOR UPDATE;
это типа: сначала делаю нужный мне рандомный простой селект одной строки, потом ее конкретно выбираю селектом уже с локом. но не прокатило.

Sterx: простота заебись, но многие вещи когда можно повесить на бд - стараюсь вешать. один раз поебался погуглил, потом забыл и оно работает. тем более у иннодб есть прилады свои


Эта страница в полной версии