Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 31/03/11 в 19:29 |
Товарищи как строку на чтение заблокировать? Скрипт выбирает строку из базы. ее локает. потом разлокает.
типа:
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;
По идее одно из значений выбирается, второе значение по идее должно выбираться во втором клиенте. но результат тот же.
Или я не тем путем иду?
|
|
пришел к победе коммунистического труда
|
0
|
|
|
programmer
С нами с 08.12.02
Сообщения: 7615
Рейтинг: 5760
|
Добавлено: 31/03/11 в 21:00 |
а вот если гипотетически скрипт в процессе прервет выполнение. строка так и останется локнутой?
|
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 31/03/11 в 21:32 |
разлочит
|
|
пришел к победе коммунистического труда
|
0
|
|
|
www.phpdevs.com
С нами с 24.10.02
Сообщения: 16633
Рейтинг: 16105
|
Добавлено: 31/03/11 в 21:40 |
|
|
Пишу на php/mysql/django за вменяемые деньги.
Обращаться в личку.
|
5
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 31/03/11 в 21:58 |
ну хочу выбрать селектом строку. ее залочить. чтобы другой экземпляр скрипта эту же строку не выбрал.
крон:
*/5 * * * * php script1.php
*/5 * * * * php script2.php
база:
10 строк в таблице
script1.php:
берет рандомно одну строку.
лочит.
с ней работает.
разлочивает.
script1.php:
берет рандомно одну строку. (не должен взять залоченную первым скриптом).
лочит.
с ней работает.
разлочивает.
за линк спасибо. курю
|
|
пришел к победе коммунистического труда
|
0
|
|
|
С нами с 20.02.06
Сообщения: 248
Рейтинг: 366
|
Добавлено: 31/03/11 в 23:42 |
Так а при чём тут это? Лок строки не помешает второму клиенту выбрать ту же самую строку, он просто будет ждать освобождения лока. Тут надо действовать по-другому. Например, в каком-нибудь файле или даже в бд записать id выбранной первым скриптом строки, а во втором сделать условие (SELECT ... WHERE id != ид_выбранное_первым_скриптом). Как-то так, если я правильно понял задачу
|
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 01/04/11 в 11:31 |
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
|
|
пришел к победе коммунистического труда
|
0
|
|
|
programmer
С нами с 08.12.02
Сообщения: 7615
Рейтинг: 5760
|
Добавлено: 01/04/11 в 12:28 |
неужели нельзя тупо помечать произвольный флаг в записи. транзакции блин юзать. простота залог здоровья
|
|
|
|
С нами с 05.04.07
Сообщения: 1661
Рейтинг: 1090
|
Добавлено: 01/04/11 в 12:53 |
а так не пройдёт чтоли?
Код: | SELECT * FROM t WHERE id=(SELECT id FROM t WHERE lockFiled=0 ORDER BY RAND() LIMIT 1) FOR UPDATE; |
|
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 01/04/11 в 22:20 |
taj: да это понятно. с локом то. Запрос
SELECT * FROM t WHERE a=(SELECT a FROM t ORDER BY RAND() LIMIT 1) FOR UPDATE;
это типа: сначала делаю нужный мне рандомный простой селект одной строки, потом ее конкретно выбираю селектом уже с локом. но не прокатило.
Sterx: простота заебись, но многие вещи когда можно повесить на бд - стараюсь вешать. один раз поебался погуглил, потом забыл и оно работает. тем более у иннодб есть прилады свои
|
|
пришел к победе коммунистического труда
|
0
|
|
|