Транзакций конкурентов в MySQL


Я работаю в системе, что мне нужно отдать несколько данных(купоны) таблицы и вернуться к пользователю, но я не могу рисковать, поставить такой же купон, чтобы другой пользователь.

я Думал об использовании GET_LOCK() MySQL, чтобы заблокировать таблицу, временно, во время розыгрыша будет сделано, но он не безопасное HTTP-соединение, и соединение теряется, приходится звонить снова.

Есть ли способ правильно или просто лучше сделать это?

Author: Raul Mangolin, 2014-02-07

2 answers

Согласен с @mlemos, вы никогда не должны работать с LOCK TABLES в приложениях, за исключением ситуаций, многие конкретные.

Ситуациях, таким образом, нужно узнать немного схему сделки с банком.
MySQL-это не мой "сильный", но концепция для базы данных OLTP является универсальным.

В случае с MySQL, что при всем уважении, но это "лоскутное одеяло", этот ответ будет просто проверяет, если вы используете engine innoDB.

, Здесь контроль lock будет через SQL, при регистрации в таблицы, которые вы сможете использовать, чтобы контролировать, что "Этот купон уже был разыгран".

Во-Первых, вы должны беспокоиться о SET ISOLATION, он будет определять, как сеанс должен вести себя во время доступа к данным.
В этом случае я бы порекомендовал : set session transaction isolation level read committed;
Для более подробной информации прочитать в руководстве MySQL здесь.
Этот isolation level будет гарантировать, что вы будете только читать данные, которые comitados/зафиксированы в базе.

Во-Вторых, определять time-out, что их сделка будет ждать lock.
Это служит для обновления , если соревнуйтесь с другой, имеет тайм-аут, чтобы ждать освобождения в реестре.
В MySQL это делается с помощью команды set session innodb_lock_wait_timeout=10
Здесь настроена так, чтобы 10 секунд, что я считаю более, чем достаточно.
Если вам не достаточно, вы можете увеличить это время, и/или необходимо подготовить вашего приложения, чтобы обработать исключение ERROR HY000: Lock wait timeout exceeded; try restarting transaction Для более подробной информации прочитать в руководстве MySQL здесь

Третий, отключите фиксации, так что вы можете иметь больше контроля над сделки, когда он начинается и когда она должна закончиться. Для этого использовать SET autocommit = 0

Номер, запустить транзакцию start transaction и begin work.
Неважно, какой из двух команд, так как они синоним.
Но главное здесь, иметь в виду, что все, что можно изменить в базе данных, остававшийся с lock активным до тех пор, пока сделка завершится!

Пятая, выполнять update, что позволит сохранить информацию, что cupon X был разыгран.
Это является важной частью логики, и, как вы, не разместил ни один пример таблицы, структура, SQL, который использовался буду публиковать что-то из моего воображения.

update cupons set sorteado=134 where sorteado is null and cupom_id = 4444 ; 

, Объясняя:

  • столбец разыгран-это флаг, который говорит, если купон уже был разыгран. его содержание-это количество розыгрыша (так что вы можете связать то розыгрыш день/час Х с помощью купона, Y)
  • cupom_id это ключевое поле купона, в случае, если 4444 бы такой купон, участвующий в розыгрыше. Естественно, вы должны иметь свою логику для этого...
  • where sorteado is null для ног на "грааль".
    Он позволит свести к минимуму шанс получить купон, который проходит разыгран точно в тот же момент, но все же это может происходит, если это происходит, лечение LOCK SQL вступит в действие, и избежать обновить этот купон потому что ваш сеанс будет "зависать" и ждать, пока другая транзакция закончить (из-за тайм-аут настроен), когда другая транзакция закончить, это возвращается к активной и должна определить, что столбец будет разыгран был заполнен, а именно, "is not null" и не будет обновлять ничего, ноль записей.

То "грааль", "is null" в столбце разыгран + контроль сделка.

Шестой , проверить, сколько строк были обновлены в update выше, если он равен 1, значит, что все получилось... в противном случае, отдать другой купон...
Для этого используйте функцию количество_строк().
Для более подробной информации прочитать в руководстве MySQL здесь.

Setimo, завершить сделку с commit rollback, согласно его логике.


, иллюстрирующий последовательность команд, где я же в параллельные сессии..

mysql> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> create table cupons (cupom_id integer, sorteado integer);
Query OK, 0 rows affected (0.03 sec)

mysql>
mysql> insert into cupons (cupom_id) values (1),(2),(3),(4),(5);
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_lock_wait_timeout=60;
Query OK, 0 rows affected (0.00 sec)

mysql> SET autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> begin work;
Query OK, 0 rows affected (0.00 sec)

-- aqui em outra sessão executei o mesmo update com os mesmos 
-- parametros de sessao exemplificado aqui..
-- depois de executar o update aqui, na outra sessão comitei a transação.
-- observe o tempo do update abaixo e a qtde de linhas atualizadas.
mysql> update cupons set sorteado=134 where sorteado is null and cupom_id = 4;
Query OK, 0 rows affected (11.14 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
 6
Author: ceinmart, 2014-02-09 19:51:12

Вы не должны уловить таблиц с помощью LOCK TABLES и в обычных приложениях. Вам необходимо использовать транзакции с уровнем изоляции правильным, чтобы предотвратить доступ одновременно изменять одни и те же записи.

См. здесь этот другой ответ гарантировать accesso integro таблица с транзакциями.

 4
Author: mlemos, 2017-04-13 12:59:39