首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >PHP +锁定MySQL表失败

PHP +锁定MySQL表失败
EN

Stack Overflow用户
提问于 2012-08-16 12:18:11
回答 3查看 1.3K关注 0票数 1

我有一个表,它需要被锁定以防止插入,但它也需要能够在阻止插入的同时进行更新。

代码语言:javascript
复制
function myfunction() {
  $locked = mysql_result(mysql_query("SELECT locked FROM mylock"),0,0);
  if ( $locked ) return false;
  mysql_query("LOCK TABLES mylock WRITE");
  mysql_query("UPDATE mylock SET locked=1");
  mysql_query("UNLOCK TABLES");

  /* I'm checking another table to see if a record doesn't exist already */
  /* If it doesn't exist then I'm inserting that record */

  mysql_query("LOCK TABLES mylock WRITE");
  mysql_query("UPDATE mylock SET locked=0");
  mysql_query("UNLOCK TABLES");  
}

但这还不够,从另一个脚本再次调用该函数,并同时从对该函数的两次调用中插入,我不能这样做,因为它会导致重复的记录。

这很紧急,请帮帮忙。我想在字段上使用UNIQUE,但是有两个字段(player1,player2),而且这两个字段都不能包含重复的播放器ID。

不想要的行为:记录A=( Player1: 123 Player2: 456 )记录B=( Player1: 456 Player2: 123 )

EN

回答 3

Stack Overflow用户

发布于 2012-08-16 13:00:06

我刚刚注意到你的代码中有一个竞态问题。假设没有错误(请参阅我的评论)...两个进程可以检查并得到“未锁定”的结果。“锁表”将序列化它们的访问,但它们都会继续认为它们拥有锁,从而复制记录。

您可以将其重写为:

代码语言:javascript
复制
mysql_query("LOCK TABLES mylock WRITE");
mysql_query("UPDATE mylock SET locked=1 WHERE locked=0");
$have_lock = mysql_affected_rows() > 0;
mysql_query("UNLOCK TABLES");
if (!$have_lock ) return false;
票数 1
EN

Stack Overflow用户

发布于 2012-08-16 12:29:07

我建议根本不使用锁。相反,在安装数据时,请执行以下操作:

代码语言:javascript
复制
mysql_query("INSERT IGNORE INTO my_table VALUES(<some values here>)");
if(mysql_affected_rows()>0)
{
    // the data was inserted without error
    $last_id = mysql_insert_id();
    // add what you need here
}
else
{
    // the data could not be inserted (because it already exists in the table)
    // query the table to retrieve the data
    mysql_query("SELECT * FROM my_table WHERE <some_condition>");
    // add what you need here
}

INSERT语句添加IGNORE关键字时,MySQL将尝试插入数据。如果因为表中已经存在具有相同主键的记录而无法工作,它将静默失败。mysql_affected_rows用于知道插入的记录的数量并决定要做什么。

票数 0
EN

Stack Overflow用户

发布于 2012-08-16 12:37:55

这里不需要表级别的锁定,最好使用行级别的锁定。行级锁定意味着只锁定他们正在修改的一行。通常的替代方法是在修改期间锁定整个表,或者锁定表的某个子集。行级锁定只是将行的子集减少到仍然确保完整性的最小数量。

在InnoDB事务模型中,目标是将多版本数据库的最佳属性与传统的两阶段锁定结合起来。默认情况下,InnoDB在行级执行锁定,并以Oracle风格作为非锁定一致读取来运行查询。InnoDB中的锁表的存储空间非常高效,因此不需要进行锁升级:通常,允许多个用户锁定InnoDB表中的每一行或任何随机行的子集,而不会导致InnoDB内存耗尽。

如果您的问题尚未解决,那么内存大小可能是问题所在。InnoDB将其锁表存储在主缓冲池中。这意味着您可以同时拥有的锁的数量受到启动MySQL时设置的innodb_buffer_pool_size变量的限制。默认情况下,MySQL会将其保留为8MB,如果您在服务器上使用InnoDB执行任何操作,这是非常无用的。

幸运的是,这个问题的修复非常简单:将innodb_buffer_pool_size调整为一个更合理的值。但是,修复需要重新启动MySQL守护进程。根本没有办法动态调整这个变量(在撰写本文时,使用当前稳定的MySQL版本)。

在调整该变量之前,请确保您的服务器能够处理额外的内存使用。如果您将其设置为大约1 1GB,MySQL将不会预先使用所有这些空间。随着MySQL找到更多要放入缓冲区的内容,内存使用量将逐渐增加,直到达到1 1GB。此时,当需要提供新数据时,最旧和最少使用的数据开始被修剪。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11980650

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档