Кажется, что MySQL блокирует строку при выполнении последовательного чтения и сохранения вывода переменной [duplicate]

Здесь было много полезных ответов, в целом достигающих высшей точки в два пункта.

  1. BACKTICKS() `используются вокруг имен идентификаторов.
  2. QUOTES(') используются вокруг значений.

И как @MichaelBerkowski сказал

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

Существует случай, когда идентификатор не может быть зарезервированным ключевым словом или содержать символы whitespace или за пределами ограниченного набора , но обязательно требует обратных ссылок вокруг их.

ПРИМЕР

123E10 является допустимым именем идентификатора, а также действительным INTEGER литералом.

[Не вдаваясь в подробности, как вы могли бы получить такое имя идентификатора] Предположим, что я хочу создать временную таблицу с именем 123456e6.

Нет ОШИБКИ на обратных циклах.

DB [XXX]> create temporary table `123456e6` (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

ОШИБКА, если вы не используете обратные ссылки.

DB [XXX]> create temporary table 123451e6 (`id` char (8));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '123451e6 (`id` char (8))' at line 1

Однако 123451a6 [* g15]

DB [XXX]> create temporary table 123451a6 (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

Это полностью, потому что 1234156e6 также является показательным номером.

8
задан Bill Karwin 1 May 2014 в 18:57
поделиться

2 ответа

Для того, что это стоит, эта блокировка не ограничена READ-UNCOMMITTED:

mysql1> show variables like '%isolation%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
mysql1> BEGIN;
mysql1> SET @x := (SELECT x FROM foo LIMIT 1);

mysql2> UPDATE foo SET x = x+1;
[gets a lock wait]

mysql3> SHOW ENGINE INNODB STATUS;
...
---TRANSACTION 228746, ACTIVE 22 sec
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 58, OS thread handle 0x7fc262a1c700, query id 8163
  192.168.56.1 root cleaning up
TABLE LOCK table `test`.`foo` trx id 228746 lock mode IS
RECORD LOCKS space id 801 page no 3 n bits 80 index `PRIMARY` 
  of table `test`.`foo` trx id 228746 lock mode S
...

Как обсуждалось в ошибке, которую вы регистрировали, Ошибка # 67452 Установка переменной из select приобретает блокировка при использовании read uncommitted , это поведение, вероятно, по дизайну. Кажется, что она относится к той же категории, что и SELECT, результаты которой используются для изменения данных, как описано выше:

http://dev.mysql.com/doc/refman/ 5.6 / ru / innodb-locks-set.html

Когда в конструкциях REPLACE INTO t SELECT ... FROM s WHERE ... или UPDATE t ... WHERE col IN (SELECT ... FROM s ...) используется SELECT, InnoDB устанавливает общие блокировки следующих клавиш в строках из таблицы s.

Причина блокировки следующей клавиши - сделать результаты SELECT более стабильными. То есть мы не хотим, чтобы строки, сопоставляемые SELECT, менялись, когда они используются для UPDATE или другого оператора, изменяющего данные.

Даже если tx_isolation REPEATABLE-READ , это важно, потому что InnoDB не поддерживает REPEATABLE-READ для операторов SELECT, когда они выполняются как часть любого типа UPDATE.


. Ваш комментарий:

Независимо от документации, вот что происходит:

Когда вы выполняете простой оператор SELECT, InnoDB ничего не блокирует в любой изоляции транзакции, кроме SERIALIZABLE.

Если вы выполняете SELECT ... LOCK IN SHARE MODE или SELECT ... FOR UPDATE, он блокируется, конечно.

Но когда вы выполняете SELECT как часть инструкции, изменяющей данные, например INSERT INTO...SELECT или в подзапросе UPDATE или, как вы обнаружили в SET @variable := (SELECT...), он использует общую блокировку, чтобы убедиться, что данные не изменяются во время обновления.

Документация может быть неполный. Лучше проверить.

2
ответ дан Bill Karwin 24 August 2018 в 16:35
поделиться

Ваш первый оператор выполняет SELECT в таблице, поэтому транзакция получает блокировку чтения в одной строке. Вторая транзакция пытается получить блокировку записи в той же таблице (для всех строк, поскольку нет предложения WHERE), но не может. Вам необходимо выдать команду COMMIT (или ROLLBACK) после SET @x = (...), чтобы она освободила блокировку чтения.

Вышеуказанное неверно. Я сохраняю этот пост только потому, что могут быть интересны следующие комментарии.

0
ответ дан RandomSeed 24 August 2018 в 16:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: