В MySql 8.0 я обрабатываю «атомарный счетчик» (в хранимой процедуре) и этот простой обходной путь (я не могу использовать транзакции) прекрасно работает для моей цели:
CREATE PROCEDURE xxx...
...
UPDATE cnt SET value = (@val := value + 1) where id = 1;
...
но когда я компилирую процедуру, я получаю это предупреждение
Setting user variables within expressions is deprecated and will be removed in a future release. ...
Как я могу избежать предупреждающего сообщения? (я не могу узнать "новый" синтаксис)
Ну, это в названии: удаление предупреждающего сообщения, когда я делаю «атомарный счетчик» или атомарное приращение (если хотите)






Имитация атомарного счетчика без необходимости установки переменных в выражениях может быть достигнута с помощью
repeat
select value + 1 into @value from cnt where id = 1;
update cnt set value = @value where id = 1 and value = @value - 1;
until (select row_count()) > 0 end repeat;
На самом деле это не атомарно (поскольку другой сеанс может увеличить счетчик между select и update), но он будет обновляться только в том случае, если этого не произошло, в противном случае он будет повторять попытку (возможно, на неопределенный срок, если у вас действительно очень занят счетчик). row_count() используется для проверки того, произошло ли это обновление.
Для этой устаревшей функции нет «нового синтаксиса» — это будет намеренно невозможно сделать в MySQL 9 (поэтому предупреждение), см. журнал изменений. Основным вариантом использования для установки пользовательских переменных в выражениях было моделирование CTE (например, рекурсивный иерархический запрос или rank() оконная функция), и с поддержка CTE в MySQL 8 можно было отказаться от этой функции.
Для контекста предполагаемое поведение вашего синтаксиса состоит в том, чтобы сделать
UPDATE cnt SET value = value + 1 where id = 1;
SELECT value INTO @val from cnt where id = 1;
вести себя атомарно.
Очевидно, ожидаемый способ добиться этого — использовать транзакцию, поэтому не будет нового синтаксиса для замены вашего поведения, как это требовалось для CTE; однако вы можете проверить, не исчезла ли причина, по которой вы не можете использовать транзакцию, в более новой версии MySQL (с потенциально новыми возможностями).
Просто для уточнения: цикл действует как атомарный счетчик и работает без устаревшего синтаксиса и без транзакций. (Все 4 строки заменяют вашу единственную строку). Остальные просто комментируют Я не могу узнать "новый" синтаксис": новый синтаксис для моделирования cte -> ctes. новый синтаксис для моделирования транзакций: transaction. (И поэтому разработчики не планируют новый синтаксис для замены вашего текущего однострочника новым).
Что, если сеансы два обновят значение в момент между вашим выбором и вашим обновлением? Тогда ваш код выше вернет приращение.
@BillKarwin Если другой сеанс обновил промежуточный счетчик, то у него больше не будет value = @value - 1 (для where-условия), поэтому он не будет обновлять строку (и row_count() будет равен 0, выполняя еще одну итерацию).
Хорошо, да, я вижу.
Предупреждение касается установки переменных сеанса как побочного эффекта выражения в вашем операторе UPDATE. Этого можно избежать, переместив назначение переменной в последующую инструкцию SELECT.
START TRANSACTION;
UPDATE cnt SET value = value + 1 where id = 1;
SELECT value INTO @val FROM cnt WHERE id =1;
COMMIT;
Это не будет иметь риска состояния гонки, если вы начнете транзакцию до UPDATE и выполните SELECT в той же транзакции. Блокировка, полученная с помощью UPDATE, не позволит другому параллельному сеансу обновить ту же строку до того, как вы сможете выбрать значение.
Почему нельзя использовать транзакции? Это действительно фундаментальная вещь, от которой нужно отказаться при использовании реляционной базы данных.
Я согласен, но в моем случае блокировки снижают общую производительность (среди прочего)
Хорошо, у вас есть некоторые недоразумения, я думаю. MySQL всегда блокирует строки для обновлений, независимо от того, начинаете ли вы явно и фиксируете транзакции или просто полагаетесь на автоматическую фиксацию. На самом деле, автофиксация по-прежнему использует транзакции, просто они фиксируются сразу после завершения обновления SQL. Но они по-прежнему подлежат блокировке. Вам не нужно держать транзакции открытыми в течение длительного времени, на самом деле, как правило, лучше фиксировать их как можно быстрее. Но выполнение двух операторов SQL подряд, как показано выше, не должно занимать слишком много времени. Просто зафиксируйте сразу после этого.
Также у вас может быть сочетание — то есть по умолчанию для автоматической фиксации в большинстве ваших приложений, и просто используйте явный запуск и фиксацию, когда вам нужно инкапсулировать работу для последовательности операторов, как пример в моем ответе.
Хорошо, Билл, я знаю, что такое транзакция ;) Но для меня это не вариант. На самом деле решение, данное Solarflare, довольно хорошее. Спасибо за помощь.
Я понятия не имею, что вы пытаетесь сделать, можете привести примеры?