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:
простота заебись, но многие вещи когда можно повесить на бд - стараюсь вешать. один раз поебался погуглил, потом забыл и оно работает. тем более у иннодб есть прилады свои
Новая тема
Ответить
Эта страница в полной версии