php - MYSQL:简单查询死锁

标签 php mysql deadlock

我有一个表“点击”,每次用户导航特殊计数器脚本 click.php 时我都会在其中添加记录。该表没有自动增量列,它以 transaction_id CHAR(32) 作为主键,在插入新记录之前随机生成。每个新记录都有列 normalized=0

每 3 分钟后台守护进程启动一次事务,读取所有新的点击 WHERE normalized=0 并将其分组到表 stats 中。该表的唯一写入查询是在所有处理结束时执行的UPDATE clicks SET normalized=1 WHERE normalized=0,然后提交事务。

问题是,每次在此事务期间导航 click.php 时,脚本都无法向“clicks”添加新记录,并且会失败并出现错误:

SQLSTATE[40001]: Serialization failure: 
1213 Deadlock found when trying to get lock; try restarting transaction

    INSERT  `clicks` 
    SET `transaction_id`='3520359d597ba05b635ff15feb334229',
        `time`='2016-04-29 15:14:31', 
        ...,
        `normalized`='0' 

我知道我可以使用LOCK TABLES解决这个问题,但我只想知道为什么会发生这种死锁。

更新: 我在 SHOW ENGINE INNODB STATUS 输出中看到以下原因:

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 252763 page no 124 n bits 480 index `normalized` 
of table `tds`.`clicks` trx id C1329EF lock_mode X locks gap before 
rec insert intention waiting

最佳答案

(这应该是一条评论,但它又长又复杂)

什么是事务隔离模式?

我以前从未遇到过这种情况 - 主要是因为我避免使用多语句事务,例如

UPDATE clicks 
SET normalized=2
WHERE normalized=0; 

INSERT INTO stats (transaction_id, clicks)
SELECT transaction_id, COUNT(*)
FROM clicks 
WHERE normalized=2
GROUP BY transaction_id;

UPDATE clicks
SET transaction_id=1
WHERE transaction_id=2;

如果您使用单独的列和为数据集生成的标识符,可以通过对点击表进行一次更新来实现此目的。如果您从 cron 运行它,您可能应该将它们包装在 GET_LOCK()...RELEASE_LOCK() 循环中以防止并发。尽管该模型确实支持大多数事务模型的并发性,但当事情已经变得很糟糕时,它的性能会受到一些影响。

关于php - MYSQL:简单查询死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36939100/

相关文章:

javascript - php代码不获取表单输入值?

php - 尝试将文本字段中的数据插入数据库时​​出现 MySQL 错误

mysql - 字符串截断长度,但不允许切碎单词

java - 谁能帮我从我的 mysql 推文数据库中删除停用词

java - 如何使用 NetBeans 消除 Java 代码中的死锁

java - 为什么我的 Cassandra 节点卡在 MutationStage 增加的情况下?

php - Laravel 5.2 理解 "fat model, skinny controller"

javascript - PHP 通过按钮传递值的最佳实践

php - 为什么这个 PHP 脚本显示 ' Webpage Not Available '

logging - Umbraco数据库日志错误:找不到任何nodeId = 0的页面