Mysql:锁定表以在值更新之前读取

拍子

在我的数据库(MySQL)中,我有一个表(MyISAM),其中包含一个名为number的字段。该字段的每个值可以是0或正数。非零值必须是唯一的。最后一件事是该字段的值是根据此表中另一个字段(称为isNew)的值在我的php代码中生成的。代码遵循。

$maxNumber = $db->selectField('select max(number)+1 m from confirmed where isNew = ?', array($isNew), 'm');
$db->query('update confirmed set number = ? where dataid = ?', array($maxNumber, $id));

代码的第一行选择数字字段的最大值并将其递增。第二行通过设置记录的新生成的编号来更新记录。

数百个客户端正在同时使用此代码,因此我注意到有时出现重复的数字字段。据我了解,这是在两个客户端几乎同时读取number字段的值并且导致重复的情况下发生的。

我已经阅读了有关SELECT ... FOR UPDATE语句的信息,但是我不确定它是否适用于我的情况。

所以问题是我应该只将FOR UPDATE附加到我的SELECT语句上吗?还是创建一个存储过程来完成这项工作?还是完全改变了数字的生成方式?

琼斯

这绝对是可以做到的。MyISAM不提供事务锁定功能,因此无需考虑FOR UPDATE示例代码中的两个语句之间肯定存在争用条件的空间。您实现它的方式就像说话的Burro。令人惊奇的是,它完全可以工作,而不是效果很差!:-)

我不明白您在使用此SQL做什么:

 select max(number)+1 m from confirmed where isNew = ?

number唯一值是在整个表中还是仅在isNew具有特定值的集合内如果number整个表中的值都是唯一的,那会起作用吗?这将更易于创建,调试和维护。

您需要一种获取号码的多连接安全方式。

您可以尝试使用此SQL。它将在一条语句中设置最大数量。

 UPDATE confirmed 
    SET number = (SELECT 1+ MAX(number) FROM confirmed WHERE isNew = ?)
  WHERE dataid = ?

这将导致性能下降。如果没有上的复合索引(isNew, number),并且没有声明NOT NULL两个列,它将执行非常非常差的操作。

如果可以使用整个表格中唯一的数字,建议您为自己创建一个sequence设置,该设置将在您每次使用时返回唯一的数字。您需要使用一系列连续的SQL语句来执行此操作。这是怎么回事。

首先,当您创建表时,请创建一个要使用的表sequence(或您喜欢的任何名称)。这是一个单列表。

CREATE TABLE sequence (
     sequence_id INT NOT NULL AUTO_INCREMENT,
     PRIMARY KEY (`sequence_id`)
) AUTO_INCREMENT = 990000

这将使序列表开始发行编号为990,000的数字。

其次,当您在应用程序中需要唯一编号时,请执行以下操作。

INSERT INTO sequence () VALUES ();
DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
UPDATE confirmed 
    SET number = LAST_INSERT_ID()
  WHERE dataid = ?

这里发生了什么?MySQL函数LAST_INSERT_ID()返回最近自动生成的ID编号的值。因为您在该sequence表中插入了一行,所以它会返回生成的ID号。DELETE FROM命令可防止该表占用磁盘空间。我们不在乎旧的ID号。

LAST_INSERT_ID()是连接安全的。如果与数据库不同连接上的软件都使用它,则它们都将获得自己的值。

如果您需要知道最后插入的ID号,则可以发出以下SQL:

SELECT LAST_INSERT_ID() AS sequence_id

您将得到退货。

如果您使用的是Oracle或PostgreSQL,而不是MySQL,则会发现它们提供了SEQUENCE对象,这些对象基本上就是这样做的。

这是另一个类似问题的答案。

生成11,000,000个唯一ID的最快方法

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章