欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

PDOException:SQLSTATE [40001]:序列化失败:1213 尝试获取锁时发现死锁;

修改于 10 年零 7 个月前    
浏览 9k 次    
5
               

我的 D7 站点出现以下错误:                    

PDOException: SQLSTATE[40001]: Serialization failure: 1213 
Deadlock found when  trying to get lock; try restarting transaction: 
INSERT INTO {node} (type, language, title, uid, status, created, changed, promote, sticky) 
VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, 
:db_insert_placeholder_3, :db_insert_placeholder_4,
:db_insert_placeholder_5, :db_insert_placeholder_6,
:db_insert_placeholder_7, :db_insert_placeholder_8); Array
(
[:db_insert_placeholder_0] => baby_clothes
[:db_insert_placeholder_1] => und
[:db_insert_placeholder_2] => Boys clothes and swing
[:db_insert_placeholder_3] => 1
[:db_insert_placeholder_4] => 1
[:db_insert_placeholder_5] => 1333240131
[:db_insert_placeholder_6] => 1333240131
[:db_insert_placeholder_7] => 1
[:db_insert_placeholder_8] => 0
)

in drupal_write_record() (line 6975 of includes/common.inc).
                   

我有一个模块可以在 cron 运行时以编程方式保存节点。有可能两个节点可以同时保存。这可能是造成这种情况的原因吗?表锁定机制无法正常工作以防止冲突?如果我将站点置于维护模式并只运行要保存的一批节点,这种情况永远不会发生。想法?谢谢!                    

                                   
改进这个问题                                    
2012 年 4 月 1 日 1:44 问                                
blue928的用户头像                                    
                               
  • 从哪里来Boys clothes and swing那是你的模块吗? 
    – 帕特里克肯尼                                    
     2012 年 4 月 1 日 1:49                                
  • 这些是进入数据库节点表的示例值。它们分别对应类型、语言、标题等,从上到下。 
    – 蓝928                                    
     2012 年 4 月 1 日 2:16                                
添加评论                
       

2 个回答                    

       
4
                   

这是 drupal 7.x 核心中的一个已知问题,并已在最新版本中得到解决(有关更多信息,请参阅此错误报告)。确保您已升级到最新版本的 Drupal 7,或者如果您需要让您的站点正常运行,请尝试应用补丁。                        

                                       
改进这个答案                                        
于2012 年 6 月 27 日 11:23编辑                                    
apaderno 的用户头像                                        
                                   
阿帕德诺                                        
95.5k15个金徽章158枚银徽章283枚青铜徽章                                        
2012 年 4 月 1 日 3:08 回答                                    
schnippy 的用户头像                                        
                                   
  • 不幸的是,当前版本的 Drupal 7 并没有解决这个问题。最新版本是 7.12,于 2 月发布。此修复已于 3 月下旬应用于 Drupal 核心 7.x 开发分支,但该分支并不意味着在生产站点上运行。希望 Drupal 7 的下一个正式版本能尽快推出,因为它会有这个修复。 
    – 核心转储错误                                        
     2012 年 4 月 13 日 21:55                                     
  • 1                                    
    Drupal 7.14 包含该修复程序。但是即使修复了,仍然有一些人遇到这些错误。 
    – user56reinstatemonica8                                        
     2012 年 8 月 6 日晚上 10:50                                    
  • 1                                    
    在撰写本文时,我仍然收到此错误 (7.15)。关于如何在 Drupal 之外解决此问题的更多想法? 
    – 蓝928                                        
     2012 年 9 月 30 日 23:21                                    
  • 我打开了一个关于这个的新线程。看看新线程更普遍地解决了需要解决这个性能问题的问题。drupal.stackexchange.com/questions/45617/… 
    – 蓝928                                        
     2012 年 10 月 4 日 6:52                                     
添加评论                    
       
3
                   

我也有这个问题。我意识到数据库中有一些冗余数据。删除这些后,问题解决。                        

                                       
改进这个答案                                        
2012 年 7 月 14 日 12:02 回复                                    
VivMajor的用户头像                                        
                                   
  • 你能详细说明一下吗? 
    – 国库NK                                        
     2013 年 12 月 13 日 10:56                                    
  • 1                                    
    @ Gokul NK 方法是使用备份和迁移模块备份数据库(这使得数据没有不必要的缓存数据) - 将此数据导入本地服务器上的数据库并检查是否有冗余行任何字段表(我假设您可以将其识别为开发人员)。删除这些记录并将干净的数据导入您的站点。希望能帮助到你。 
    – 活力少校                                        
     2013 年 12 月 20 日 14:15                                    

添加评论                    


                                           

修改于 10 年零 7 个月前                        
浏览 9k 次                        
5
                                   

我的 D7 站点出现以下错误:                                        

PDOException: SQLSTATE[40001]: Serialization failure: 1213 
Deadlock found when  trying to get lock; try restarting transaction: 
INSERT INTO {node} (type, language, title, uid, status, created, changed, promote, sticky) 
VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, 
:db_insert_placeholder_3, :db_insert_placeholder_4,
:db_insert_placeholder_5, :db_insert_placeholder_6,
:db_insert_placeholder_7, :db_insert_placeholder_8); Array
(
[:db_insert_placeholder_0] => baby_clothes
[:db_insert_placeholder_1] => und
[:db_insert_placeholder_2] => Boys clothes and swing
[:db_insert_placeholder_3] => 1
[:db_insert_placeholder_4] => 1
[:db_insert_placeholder_5] => 1333240131
[:db_insert_placeholder_6] => 1333240131
[:db_insert_placeholder_7] => 1
[:db_insert_placeholder_8] => 0
)

in drupal_write_record() (line 6975 of includes/common.inc).
                                       

我有一个模块可以在 cron 运行时以编程方式保存节点。有可能两个节点可以同时保存。这可能是造成这种情况的原因吗?表锁定机制无法正常工作以防止冲突?如果我将站点置于维护模式并只运行要保存的一批节点,这种情况永远不会发生。想法?谢谢!                                        

                                                       
改进这个问题                                                        
2012 年 4 月 1 日 1:44 问                                                    
blue928的用户头像                                                        
                                                   
  • 从哪里来Boys clothes and swing那是你的模块吗? 
    – 帕特里克肯尼                                                        
     2012 年 4 月 1 日 1:49                                                    
  • 这些是进入数据库节点表的示例值。它们分别对应类型、语言、标题等,从上到下。 
    – 蓝928                                                        
     2012 年 4 月 1 日 2:16                                                    
添加评论                                    
                           

2 个回答                                        

                           
4
                                       

这是 drupal 7.x 核心中的一个已知问题,并已在最新版本中得到解决(有关更多信息,请参阅此错误报告)。确保您已升级到最新版本的 Drupal 7,或者如果您需要让您的站点正常运行,请尝试应用补丁。                                            

                                                           
改进这个答案                                                            
于2012 年 6 月 27 日 11:23编辑                                                        
apaderno 的用户头像                                                            
                                                       
阿帕德诺                                                            
95.5k15个金徽章158枚银徽章283枚青铜徽章                                                            
2012 年 4 月 1 日 3:08 回答                                                        
schnippy 的用户头像                                                            
                                                       
  • 不幸的是,当前版本的 Drupal 7 并没有解决这个问题。最新版本是 7.12,于 2 月发布。此修复已于 3 月下旬应用于 Drupal 核心 7.x 开发分支,但该分支并不意味着在生产站点上运行。希望 Drupal 7 的下一个正式版本能尽快推出,因为它会有这个修复。 
    – 核心转储错误                                                            
     2012 年 4 月 13 日 21:55                                                         
  • 1                                                        
    Drupal 7.14 包含该修复程序。但是即使修复了,仍然有一些人遇到这些错误。 
    – user56reinstatemonica8                                                            
     2012 年 8 月 6 日晚上 10:50                                                        
  • 1                                                        
    在撰写本文时,我仍然收到此错误 (7.15)。关于如何在 Drupal 之外解决此问题的更多想法? 
    – 蓝928                                                            
     2012 年 9 月 30 日 23:21                                                        
  • 我打开了一个关于这个的新线程。看看新线程更普遍地解决了需要解决这个性能问题的问题。drupal.stackexchange.com/questions/45617/… 
    – 蓝928                                                            
     2012 年 10 月 4 日 6:52                                                         
添加评论                                        
                           
3
                                       

我也有这个问题。我意识到数据库中有一些冗余数据。删除这些后,问题解决。                                            

                                                           
改进这个答案                                                            
2012 年 7 月 14 日 12:02 回复                                                        
VivMajor的用户头像                                                            
                                                       
  • 你能详细说明一下吗? 
    – 国库NK                                                            
     2013 年 12 月 13 日 10:56                                                        
  • 1                                                        
    @ Gokul NK 方法是使用备份和迁移模块备份数据库(这使得数据没有不必要的缓存数据) - 将此数据导入本地服务器上的数据库并检查是否有冗余行任何字段表(我假设您可以将其识别为开发人员)。删除这些记录并将干净的数据导入您的站点。希望能帮助到你。 
    – 活力少校                                                            
     2013 年 12 月 20 日 14:15                                                        

添加评论                                        


                                       


                   

来自   https://drupal.stackexchange.com/questions/27119/pdoexception-sqlstate40001-serialization-failure-1213-deadlock-found-when-t



Asked 
Modified 10 years, 7 months ago    
Viewed 9k times
5
               

I am getting the following error on my D7 site:

PDOException: SQLSTATE[40001]: Serialization failure: 1213 
Deadlock found when  trying to get lock; try restarting transaction: 
INSERT INTO {node} (type, language, title, uid, status, created, changed, promote, sticky) 
VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, 
:db_insert_placeholder_3, :db_insert_placeholder_4,
:db_insert_placeholder_5, :db_insert_placeholder_6,
:db_insert_placeholder_7, :db_insert_placeholder_8); Array
(
[:db_insert_placeholder_0] => baby_clothes
[:db_insert_placeholder_1] => und
[:db_insert_placeholder_2] => Boys clothes and swing
[:db_insert_placeholder_3] => 1
[:db_insert_placeholder_4] => 1
[:db_insert_placeholder_5] => 1333240131
[:db_insert_placeholder_6] => 1333240131
[:db_insert_placeholder_7] => 1
[:db_insert_placeholder_8] => 0
)

in drupal_write_record() (line 6975 of includes/common.inc).
                   

I have a module that saves nodes programatically on cron run. There is the possibiliy that two nodes could save simultaneously. Is that what could be causing this? The table locking mechanism is not working correctly to prevent collisions? If I put the site in maintenance mode and just run the batch of nodes to be saved, this never happens. Thoughts? thanks!

                                   
Improve this question                                    
asked Apr 1, 2012 at 1:44                                
blue928's user avatar                                    
                               
  • Where does the Boys clothes and swing come from? Is that from your module? 
    – Patrick Kenny                                    
     Apr 1, 2012 at 1:49                                
  • Those are example values of what is going into the database node table. They correspond respectively to type, language, title, etc, going top to bottom. 
    – blue928                                    
     Apr 1, 2012 at 2:16                                
Add a comment                
       

2 Answers

       
4
                   

This is a known issue in drupal 7.x core and has been resolved in the latest release (see this bug report for more information). Make sure you've upgraded to the latest version of Drupal 7, or try applying the patch if you need to get your site operational.

                                       
Improve this answer                                        
edited Jun 27, 2012 at 11:23                                    
apaderno's user avatar                                        
                                   
apaderno                                        
95.5k15 gold badges158 silver badges283 bronze badges                                        
answered Apr 1, 2012 at 3:08                                    
schnippy's user avatar                                        
                                   
  • Unfortunately, it's not true that the current release of Drupal 7 has the fix for this issue. The most recent release is 7.12, which came out in February. This fix was applied to the Drupal core 7.x dev branch in late March, but that branch is not meant to be run on production sites. Hopefully, the next official release of Drupal 7 will be pushed out soon, as it will have this fix. 
    – coredumperror                                        
     Apr 13, 2012 at 21:55                                     
  • 1                                    
    Drupal 7.14 contains that fix. But there are still some people encountering these errors even with the fix. 
    – user56reinstatemonica8                                        
     Aug 6, 2012 at 22:50                                    
  • 1                                    
    As of this writing, I am still getting this error (7.15). More thoughts on how to fix this outside of Drupal? 
    – blue928                                        
     Sep 30, 2012 at 23:21                                    
  • I opened a new thread concerning this. Have a look as the new thread more generically addresses needing to get around this as a performance issue. drupal.stackexchange.com/questions/45617/… 
    – blue928                                        
     Oct 4, 2012 at 6:52                                     
Add a comment                    
       
3
                   

I was also having this problem. I realized there was some redundant data in the database. After deleting these, the problem is solved.

                                       
Improve this answer                                        
answered Jul 14, 2012 at 12:02                                    
VivMajor's user avatar                                        
                                   
  • Can you please elaborate? 
    – Gokul N K                                        
     Dec 13, 2013 at 10:56                                    
  • 1                                    
    @ Gokul N K The way to go would be to backup your database with Backup and Migrate module ( this makes the data free from unnecessary cache data) - import this data in a database on your local server and check to see if there are redundant rows in any of the field tables (this I assume you would be able to identify as the developer). Delete those records and the import teh clean data into your site. Hope it helps. 
    – VivMajor                                        
     Dec 20, 2013 at 14:15                                    
Add a comment                    
       

Your Answer

来自  https://drupal.stackexchange.com/questions/27119/pdoexception-sqlstate40001-serialization-failure-1213-deadlock-found-when-t            


           


           


           

问过 
修改于 1 年 6 个月前                
查看 526k 次                
370                                
                           

我有一个记录在线用户的 innoDB 表。它会在用户每次刷新页面时更新,以跟踪他们所在的页面以及他们上次访问该站点的日期。然后我有一个 cron 每 15 分钟运行一次以删除旧记录。                                

我在尝试锁定时遇到了“死锁”;昨晚尝试重新启动事务约 5 分钟,似乎是在向该表运行 INSERT 时。有人可以建议如何避免此错误吗?                                

===编辑===                                

以下是正在运行的查询:                                

首次访问网站:                                

INSERT INTO onlineusers SET
ip = 123.456.789.123,
datetime = now(),
userid = 321,
page = '/thispage',
area = 'thisarea',
type = 3
                               

在每个页面刷新:                                

UPDATE onlineusers SET
ips = 123.456.789.123,
datetime = now(),
userid = 321,
page = '/thispage',
area = 'thisarea',
type = 3
WHERE id = 888
                               

每 15 分钟执行一次 Cron:                                

DELETE FROM onlineusers WHERE datetime <= now() - INTERVAL 900 SECOND
                               

然后它会做一些计数来记录一些统计数据(即:在线成员,在线访客)。                                

                                               
改进这个问题                                                
于 2021 年 6 月 15 日 13:03编辑                                            
Lii的用户头像                                                
                                           
莉莉                                                
11.5k8个金徽章62枚银徽章85个青铜徽章                                                
2010 年 2 月 25 日 9:03 问                                            
大卫的用户头像                                                
                                           
  • 您能否提供有关表结构的更多详细信息?是否有聚簇索引或非聚簇索引? 
    – 安德斯·亚伯                                                
     2010 年 3 月 6 日 19:31                                            
  • 16                                            
    dev.mysql.com/doc/refman/5.1/en/innodb-deadlocks.html - 运行“show engine innodb status”将提供有用的诊断。 
    – 马丁                                                
     2010 年 3 月 7 日 5:48                                             
  • 插入单行如何导致该插入死锁?我原以为在一个事务中,您需要尝试获取至少两个锁才能死锁。插入一行只持有一个锁。我认为您从第一个查询中遗漏了一些插入或选择。 
    – 约瑟夫                                                
     2021 年 8 月 10 日 16:38                                            
添加评论                            

                   

9个答案                                

                   
357                                    
                               

可以帮助解决大多数死锁的一个简单技巧是按特定顺序对操作进行排序。                                    

当两个事务试图以相反的顺序锁定两个锁时,您会遇到死锁,即:                                    

  • 连接 1:锁定键(1),锁定键(2);

  • 连接2:锁定键(2),锁定键(1);

如果两者同时运行,连接 1 将锁定 key(1),连接 2 将锁定 key(2),每个连接将等待对方释放 key -> 死锁。                                    

现在,如果您更改了查询,以便连接将以相同的顺序锁定密钥,即:                                    

  • 连接 1:锁定键(1),锁定键(2);

  • connection 2: locks key( 1 ), locks key( 2 );

不可能陷入僵局。                                    

所以这就是我的建议:                                    

  1. 确保除了 delete 语句之外,您没有其他查询一次锁定多个键的访问。如果你这样做(我怀疑你这样做),请按升序排列它们在(k1,k2,..kn)中的位置。

  2. 修复您的删除语句以按升序工作:

改变                                    

DELETE FROM onlineusers 
WHERE datetime <= now() - INTERVAL 900 SECOND
                                   

                                   

DELETE FROM onlineusers 
WHERE id IN (
    SELECT id FROM onlineusers
    WHERE datetime <= now() - INTERVAL 900 SECOND 
    ORDER BY id
) u;
                                   

另一件要记住的事情是 MySQL 文档建议,如果出现死锁,客户端应该自动重试。您可以将此逻辑添加到您的客户端代码中。(比如说,在放弃之前重试 3 次此特定错误)。                                    

                                                   
改进这个答案                                                    
于 2021 年 6 月 15 日 12:59编辑                                                
Lii的用户头像                                                    
                                               
莉莉                                                    
11.5k8个金徽章62枚银徽章85个青铜徽章                                                    
2010 年 3 月 11 日 9:48 回答                                                
Omry Yadan的用户头像                                                    
                                               
  • 7                                                
    如果您启用了交易,则全有或全无。如果您有任何类型的异常,则可以保证整个交易没有任何影响。在那种情况下,你会想要重新启动整个事情。 
    – 奥美雅丹                                                    
     2014 年 9 月 16 日 18:18                                                
  • 8个                                                
    基于对巨大表的选择的删除比简单的删除要慢得多 
    – 热机械                                                    
     2014 年 12 月 24 日 11:40                                                
  • 5个                                                
    非常感谢你,伙计。“排序语句”提示解决了我的死锁问题。 
    – 米埃                                                    
     2015 年 6 月 25 日 21:09                                                
  • 5个                                                
    @OmryYadan 据我所知,在 MySQL 中,您无法在进行更新的同一个表的子查询中进行选择。dev.mysql.com/doc/refman/5.7/en/update.html 
    – 阿塔薛西                                                    
     2015 年 12 月 9 日 7:47                                                
  • 3个                                                
    如何对删除查询中的项目排序固定死锁? 
    – a.valchev                                                    
     2018 年 5 月 16 日 12:54                                                
显示另外7条评论                                
                   
92                                    
                               

当两个事务相互等待获取锁时,就会发生死锁。例子:                                    

  • Tx 1:锁定 A,然后锁定 B

  • Tx 2:锁定 B,然后锁定 A

关于死锁有很多问题和答案。每次插入/更新/或删除一行时,都会获取一个锁。为避免死锁,您必须确保并发事务不会按可能导致死锁的顺序更新行。一般来说,即使在不同的事务中,也总是尝试以相同的顺序获取锁(例如总是先表A,然后表B)。                                    

数据库死锁的另一个原因可能是缺少索引当插入/更新/删除一行时,数据库需要检查关系约束,即确保关系一致。为此,数据库需要检查相关表中的外键。可能会导致获取其他锁而不是被修改的行。然后确保始终在外键(当然还有主键)上建立索引,否则可能会导致表锁而不是行锁如果发生表锁,锁竞争会更高,死锁的可能性会增加。                                    

                                                   
改进这个答案                                                    
2013 年 8 月 7 日 12:17编辑                                                
fedorqui 的用户头像                                                    
                                               
软呢帽                                                    
267k101枚金徽章538银徽章589枚青铜徽章                                                    
2010 年 2 月 25 日 9:21 回答                                                
ewernli的用户头像                                                    
                                               
  • 3个                                                
    所以也许我的问题是用户刷新了页面,因此在 cron 试图在记录上运行 DELETE 的同时触发了记录的更新。但是,我在插入时遇到错误,因此 cron 不会删除刚刚创建的记录。那么一条还没有插入的记录怎么会发生死锁呢? 
    – 大卫                                                    
     2010 年 2 月 25 日 9:32                                                
  • 您能否提供更多有关表的信息以及事务的具体作用? 
    – 埃文利                                                    
     2010 年 2 月 25 日 9:42                                                
  • 如果每个事务只有一个语句,我不明白死锁是如何发生的。其他表没有其他操作?没有特殊的外键或唯一约束?没有级联删除约束? 
    – 埃文利                                                    
     2010 年 2 月 25 日 10:56                                                
  • 不,没什么特别的……我想这取决于表格的使用性质。访问者每次刷新页面都会插入/更新一行。任何时候都有大约 1000 多名访客在线。 
    – 大卫                                                    
     2010 年 3 月 4 日 9:28                                                
添加评论                                
                   
15                                    
                               

如果有人仍在为这个问题苦苦挣扎:                                    

我遇到了类似的问题,即 2 个请求同时到达服务器。没有出现如下情况:                                    

T1:
    BEGIN TRANSACTION
    INSERT TABLE A
    INSERT TABLE B
    END TRANSACTION

T2:
    BEGIN TRANSACTION
    INSERT TABLE B
    INSERT TABLE A
    END TRANSACTION
                                   

所以,我很困惑为什么会发生死锁。                                    

然后我发现因为外键,2个表之间存在父子关系。当我在子表中插入一条记录时,事务正在获取对父表行的锁定。紧接着,我试图将触发锁提升的父行更新为 EXCLUSIVE 行。由于第二个并发事务已经持有共享锁,因此导致死锁。                                    

参考:https://blog.tekenlight.com/2019/02/21/database-deadlock-mysql.html                                    

                                                   
改进这个答案                                                    
2019 年 2 月 26 日 13:41 回复                                                
chatsap的用户头像                                                    
                                               
  • 就我而言,问题似乎也是外键关系。谢谢1 
    – 克里斯普林斯                                                    
     2019 年 5 月 26 日 21:49                                                
  • 对我来说是一样的:更新了一个表,更新了另一个表中的外键。我用 No Action 删除了我的约束键。然后,奇迹,不再有死锁了!当然它不再检查约束,但它不能用于大型更新表。多谢 ! 
    – 帕特里斯                                                    
     2020 年 12 月 15 日 14:39                                                 
添加评论                                
                   
14                                    
                               

删除语句很可能会影响表中总行的很大一部分。最终这可能会导致在删除时获取表锁。持有锁(在本例中为行锁或页锁)并获取更多锁始终存在死锁风险。但是我无法解释为什么插入语句会导致锁升级——它可能与页面拆分/添加有关,但更了解 MySQL 的人将不得不在那里填写。                                    

首先,值得尝试立即为 delete 语句显式获取表锁。请参阅锁定表表锁定问题                                    

                                                   
改进这个答案                                                    
2018年3月22日17:28编辑                                                
informatik01的用户头像                                                    
                                               
资讯01                                                    
15.8k10个金徽章74枚银徽章103枚青铜徽章                                                    
2010 年 3 月 6 日 19:42 回复                                                
Anders Abel 的用户头像                                                    
                                               
添加评论                                
                   
6个                                    
                               

delete您可以尝试通过首先将要删除的每一行的键插入到临时表中来运行该作业,就像这样的伪代码                                    

create temporary table deletetemp (userid int);

insert into deletetemp (userid)
  select userid from onlineusers where datetime <= now - interval 900 second;

delete from onlineusers where userid in (select userid from deletetemp);
                                   

像这样分解它效率较低,但它避免了在delete.                                    

此外,修改您的select查询以添加一个where排除早于 900 秒的行的子句。这避免了对 cron 作业的依赖,并允许您重新安排它运行的频率较低。                                    

关于死锁的理论:我在 MySQL 方面没有太多背景知识,但是这里有……它将delete为日期时间保留一个键范围锁,以防止where在事务中间添加与其子句匹配的行,并且当它找到要删除的行时,它将尝试获取它正在修改的每个页面上的锁。insert在要插入的页面上获取锁,然后尝试获取键锁。通常情况下,他们insert会耐心等待该键锁打开,但如果尝试delete锁定正在insert使用的同一页面,这将死锁,因为delete需要该页面锁和insert需要该键锁。不过,这似乎不适合插入,delete并且insert正在使用不重叠的日期时间范围,所以可能发生了其他事情。                                    

http://dev.mysql.com/doc/refman/5.1/en/innodb-next-key-locking.html                                    

                                                   
改进这个答案                                                    
2010 年 3 月 11 日 16:26 回复                                                
Brian Sandlin 的用户头像                                                    
                                               
添加评论                                
                   
4个                                    
                               

对于使用 Spring 的 Java 程序员,我使用 AOP 方面避免了这个问题,该方面自动重试遇到瞬态死锁的事务。                                    

有关详细信息,请参阅@RetryTransaction Javadoc。                                    

                                                   
改进这个答案                                                    
2017 年 1 月 19 日 17:32编辑                                                
2013 年 6 月 29 日 14:59 回复                                                
阿奇的用户头像                                                    
                                               
添加评论                                
                   
3个                                    
                               

cron很危险。如果一个 cron 实例未能在下一个到期之前完成,它们很可能会互相争斗。                                    

最好有一个持续运行的作业,它会删除一些行,休眠一些,然后重复。                                    

此外,INDEX(datetime)对于避免死锁非常重要。                                    

但是,如果日期时间测试包括超过表的 20%,则将DELETE执行表扫描。更频繁地删除更小的块是一种解决方法。                                    

使用较小块的另一个原因是锁定较少的行。                                    

底线:                                    

  • INDEX(datetime)

  • 持续运行的任务——删除,睡一分钟,重复。

  • 为确保上述任务没有终止,有一个 cron 作业,其唯一目的是在失败时重新启动它。

其他删除技巧: http://mysql.rjweb.org/doc.php/deletebig                                    

                                                   
改进这个答案                                                    
2019 年 12 月 5 日 21:27 回答                                                
Rick James 的用户头像                                                    
                                               
添加评论                                
                   
3个                                    
                               

@Omry Yadan 的回答 ( https://stackoverflow.com/a/2423921/1810962 ) 可以通过使用 ORDER BY 来简化。                                    

改变                                    

DELETE FROM onlineusers 
WHERE datetime <= now() - INTERVAL 900 SECOND
                                   

                                   

DELETE FROM onlineusers 
WHERE datetime <= now() - INTERVAL 900 SECOND
ORDER BY ID
                                   

使您删除项目的顺序保持一致。此外,如果您在单个事务中进行多次插入,请确保它们也始终按 ID 排序。                                    

根据 mysql 删除文档:                                    

如果指定了 ORDER BY 子句,则按照指定的顺序删除行。                                        

您可以在此处找到参考资料:https ://dev.mysql.com/doc/refman/8.0/en/delete.html                                    

                                                   
改进这个答案                                                    
2021 年 8 月 10 日 16:28 回答                                                
约瑟夫的用户头像                                                    
                                               
添加评论                                
                   
2个