Атомарный счетчик с MySql

В 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. ...

Как я могу избежать предупреждающего сообщения? (я не могу узнать "новый" синтаксис)

Я понятия не имею, что вы пытаетесь сделать, можете привести примеры?

P.Salmon 16.05.2019 12:19

Ну, это в названии: удаление предупреждающего сообщения, когда я делаю «атомарный счетчик» или атомарное приращение (если хотите)

Stef 16.05.2019 12:40
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
2
502
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Имитация атомарного счетчика без необходимости установки переменных в выражениях может быть достигнута с помощью

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. (И поэтому разработчики не планируют новый синтаксис для замены вашего текущего однострочника новым).

Solarflare 18.05.2019 08:25

Что, если сеансы два обновят значение в момент между вашим выбором и вашим обновлением? Тогда ваш код выше вернет приращение.

Bill Karwin 18.05.2019 23:26

@BillKarwin Если другой сеанс обновил промежуточный счетчик, то у него больше не будет value = @value - 1 (для where-условия), поэтому он не будет обновлять строку (и row_count() будет равен 0, выполняя еще одну итерацию).

Solarflare 19.05.2019 09:12

Хорошо, да, я вижу.

Bill Karwin 19.05.2019 17:34

Предупреждение касается установки переменных сеанса как побочного эффекта выражения в вашем операторе 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, не позволит другому параллельному сеансу обновить ту же строку до того, как вы сможете выбрать значение.

Почему нельзя использовать транзакции? Это действительно фундаментальная вещь, от которой нужно отказаться при использовании реляционной базы данных.

Bill Karwin 17.05.2019 17:19

Я согласен, но в моем случае блокировки снижают общую производительность (среди прочего)

Stef 18.05.2019 09:30

Хорошо, у вас есть некоторые недоразумения, я думаю. MySQL всегда блокирует строки для обновлений, независимо от того, начинаете ли вы явно и фиксируете транзакции или просто полагаетесь на автоматическую фиксацию. На самом деле, автофиксация по-прежнему использует транзакции, просто они фиксируются сразу после завершения обновления SQL. Но они по-прежнему подлежат блокировке. Вам не нужно держать транзакции открытыми в течение длительного времени, на самом деле, как правило, лучше фиксировать их как можно быстрее. Но выполнение двух операторов SQL подряд, как показано выше, не должно занимать слишком много времени. Просто зафиксируйте сразу после этого.

Bill Karwin 18.05.2019 19:41

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

Bill Karwin 18.05.2019 19:42

Хорошо, Билл, я знаю, что такое транзакция ;) Но для меня это не вариант. На самом деле решение, данное Solarflare, довольно хорошее. Спасибо за помощь.

Stef 18.05.2019 23:08

Другие вопросы по теме