首页 > 解决方案 > 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. ...

我怎样才能避免警告信息?(我找不到“新”语法)

标签: mysqltransactions

解决方案


无需在表达式中设置变量的模拟原子计数器可以通过

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;

这实际上不是原子的(因为不同的会话可以增加和之间的计数器selectupdate,但它只会在没有发生的情况下更新,否则它会重试(如果你有一个非常忙碌的计数器,可能会无限期地重试)。row_count()用于检查该更新是否发生。

该不推荐使用的功能没有“新语法” - 有意地,在 MySQL 9 中不再可能执行此操作(因此警告),请参阅更改日志。在表达式中设置用户变量的主要用例是模拟 CTE(例如递归分层查询rank()窗口函数),并且在 MySQL 8 中 CTE 的支持下,可以弃用此功能。

对于上下文,您的语法的预期行为是使

UPDATE cnt SET value = value + 1 where id = 1; 
SELECT value INTO @val from cnt where id = 1; 

原子行为。

显然,实现这一点的预期方法是使用事务,因此不会有新的语法来替换您的行为,就像 CTE 所需要的那样;但是,您可能想检查您无法使用事务的原因是否可能在较新的 MySQL 版本中消失(具有潜在的新功能)。


推荐阅读