Натолкнулся на любопытную особенность работы блокировки в mysql. Итак дано:
таблица table-1 и table-2. Из второй мы читаем, результат записываем в первую. Но читаем не просто - а достаточно хитро, примерно так
TRUNCATE TABLE table-1; INSERT INTO table-1 SELECT * FROM table-2 WHERE flf2=(SELECT fld FROM table-2 WHERE fld3='value');
Если таблицы не заблокировать (что мне понятнее) или не использовать транзаккцию (что для случая mysql я пока не использовал), то при одновременном выполнении запроса получится ... да всё, что угодно. Имитация (запуск скрипта с вызовом указанного кода в несколько потоков) приводил к тому, например, что для ряда ситуаций число строк в table-1 превышало ожиждаемое в 1,5-2 раза.
Соответственно, требуется обернуть вызовы блокировкой. Которая по идее должна выглядеть так:
LOCK TABLES table-1 WRITE, table-2 READ; TRUNCATE TABLE table-1; INSERT INTO table-1 SELECT * FROM table-2 WHERE flf2=(SELECT fld FROM table-2 WHERE fld3='value'); UNLOCK TABLES;
Но вот фигушки. В такой конструкции mysql упорно выдает ошибку ERROR #1100: Table 'table-2' was not locked with LOCK TABLES
Как оказалось, это не бага, это фича. Как написано в документации https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html - для каждого упоминения таблицы table-2 в SELECT требуется свой блокировочный алиас в LOCK'е. Вот так примерно:
LOCK TABLES table-1 WRITE, table-2 READ, table-2 AS t2 READ; TRUNCATE TABLE table-1; INSERT INTO table-1 SELECT * FROM table-2 WHERE flf2=(SELECT fld FROM table-2 AS t2 WHERE fld3='value'); UNLOCK TABLES;
В такой конструкции - всё будет работать.
И еще момент: когда используем LOCK TABLES, то в нем надо перечислить (заблокировать) все таблицы, к которым будет доступ на чтение / запись. В противном случае mysql выдаст Error #1100. Ту самую, что какая-то таблица не блокирована, ага.