Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用复合主键和触发器自动增量的MySQL死锁_Mysql_Triggers_Deadlock_Auto Increment_Composite Primary Key - Fatal编程技术网

使用复合主键和触发器自动增量的MySQL死锁

使用复合主键和触发器自动增量的MySQL死锁,mysql,triggers,deadlock,auto-increment,composite-primary-key,Mysql,Triggers,Deadlock,Auto Increment,Composite Primary Key,我有独立的服务器和2000个在线用户(不是那么多)。 MySQL DB 5.6,带有表请求_操作(复合PK没有自动增量,但增量在触发器中,您可以在下面看到): 此表上的触发器(插入前): 我一天中有很多次死锁(例如,一天100次) LATEST DETECTED DEADLOCK ------------------------ 2019-02-21 21:09:34 7f5e11f3b700 *** (1) TRANSACTION: TRANSACTION 2947112777, ACTIVE

我有独立的服务器和2000个在线用户(不是那么多)。 MySQL DB 5.6,带有表请求_操作(复合PK没有自动增量,但增量在触发器中,您可以在下面看到):

此表上的触发器(插入前):

我一天中有很多次死锁(例如,一天100次)

LATEST DETECTED DEADLOCK
------------------------
2019-02-21 21:09:34 7f5e11f3b700
*** (1) TRANSACTION:
TRANSACTION 2947112777, ACTIVE 0 sec inserting
mysql tables in use 11, locked 11
LOCK WAIT 5 lock struct(s), heap size 1184, 3 row lock(s)
MySQL thread id 19952598, OS thread handle 0x7f5e10e38700, query id 248552715 192.168.0.7 vh_uon_com_ru
insert into request_action (
                    ra_r_id,
                    ra_u_id,
                    ra_datetime,
                    ra_text,
                    ra_datetime_reply,
                    ra_reply,
                    ra_plan,
                    cl_id,
                    ra_tr_id,
                    ra_ss_id,
                    ra_h_id,
                    ra_uch_id,
                    ra_to_u_id,
                    ra_uct_id,
                    ra_shw
                ) values (
                    40053,
                    906,
                    '2019-02-21 21:09:34',
                    'Звонок',
                    '2019-02-21 21:09:34',
                    '',
                    '0',
                    698,
                    0,
                    0,
                    0,
                    171114,
                    0,

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2320 page no 546708 n bits 104 index `PRIMARY` of table `request_action` trx id 2947112777 lock_mode X locks gap before rec insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 2947112774, ACTIVE 0 sec inserting
mysql tables in use 11, locked 11
5 lock struct(s), heap size 1184, 3 row lock(s)
MySQL thread id 19952597, OS thread handle 0x7f5e11f3b700, query id 248552705 192.168.0.7
insert into request_action (
                    ra_r_id,
                    ra_u_id,
                    ra_datetime,
                    ra_text,
                    ra_datetime_reply,
                    ra_reply,
                    ra_plan,
                    cl_id,
                    ra_tr_id,
                    ra_ss_id,
                    ra_h_id,
                    ra_uch_id,
                    ra_to_u_id,
                    ra_uct_id,
                    ra_shw
                ) values (
                    25182,
                    906,
                    '2019-02-21 21:09:34',
                    'Звонок',
                    '2019-02-21 21:09:34',
                    '',
                    '0',
                    698,
                    0,
                    0,
                    0,
                    171113,
                    0,

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 2320 page no 546708 n bits 104 index `PRIMARY` of table `request_action` trx id 2947112774 lock mode S locks gap before rec
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2320 page no 546708 n bits 104 index `PRIMARY` of table `request_action` trx id 2947112774 lock_mode X locks gap before rec insert intention waiting
*** WE ROLL BACK TRANSACTION (2)
在my.cf中,我们有以下选项:

max_connections = 10000
key_buffer_size = 1024M
join_buffer_size = 256M
read_buffer_size = 256M
sort_buffer_size = 256M
tmp_table_size = 512M
read_rnd_buffer_size = 8M
max_heap_table_size = 512M

thread_cache_size = 8192
query_cache_type = 1

query_cache_size = 15G
wait_timeout = 6000
connect_timeout = 15
interactive_timeout = 60
max_allowed_packet = 512M
bulk_insert_buffer_size = 64M

innodb_log_file_size                    = 512M
innodb_log_buffer_size                  = 2G
innodb_buffer_pool_size                 = 20G
您能帮我解决死锁问题吗?我如何解决它?我应该在死锁中重新运行查询吗?

TL;DR--当您试图为每个不同的
cl\u id
生成新的递增id时,您不能执行并发插入。必须使用表锁来执行此操作,从而导致并发插入以串行方式运行


AUTO_INCREMENT
绕过此死锁的原因是它获取了一个简短的表锁以生成下一个id。从技术上讲,这会导致所有执行INSERT的并发会话串行执行。幸运的是,表锁非常简短。默认情况下,一旦生成id,表锁就会被释放。您可以在此处阅读更多内容:

而您生成id的方法会导致死锁,因为它使用了两个锁定操作:

  • 一个用于创建行的X锁
  • 一个用于读取表的S锁。当作为INSERT/UPDATE/DELETE的一部分读取表时,将在所读取的行上创建一个共享锁
  • 但是锁不是一起获得的,两个步骤之间有一段很短的时间,这就是竞争条件发生的地方。我们可以使用两个表来演示这一点:

    mysql> create table foo ( id serial primary key);
    mysql> insert into foo (id) values (1);
    
    mysql> create table bar ( id serial primary key);
    
    mysql> create trigger b before insert on bar 
           for each row set new.id=(select max(id) from foo);
    
    现在我们在
    bar
    上有一个触发器,它将读取
    foo
    中的一些行,以获取最大值(id)

    这将使用从
    foo
    读取的值在
    bar
    中创建一个新行。但该事务仍处于打开状态

    在第二个窗口中,执行以下操作:

    mysql> update foo set id = 2;
    ...
    
    这将挂起,等待它在
    foo
    上的X锁。它无法更新
    foo
    ,因为它上已经有一个s锁,由会话放置在第一个窗口中

    返回第一个窗口并运行:

    mysql> update foo set id = 3;
    Query OK, 1 row affected (0.01 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    这会创建一个循环锁等待,这就是死锁。两个事务都在等待另一个事务持有的锁。我们在第二个窗口中看到,该事务被终止:

    mysql> update foo set id = 2;
    ...
    ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
    

    如何修复它?我应该在死锁中重新运行查询吗?

    一种解决方法是,通过在尝试插入之前获取INSERT或触发器引用的所有表上的表锁,强制并发会话串行运行

    mysql> begin;
    mysql> lock tables foo write, bar write;
    mysql> insert into bar () values ();
    
    第二个窗口挂起,但这次它挂在表锁上,而不是行锁上

    mysql> update foo set id = 2;
    ...
    
    在第一个窗口中,完成事务。解锁表锁会隐式提交事务

    mysql> unlock tables;
    
    第二个窗口停止等待,并成功完成其更新

    mysql> update foo set id = 2;
    ...
    Query OK, 1 row affected (3.50 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    注意,它已经等待了3.5秒,这是我返回第一个窗口并提交事务所花费的时间

    mysql> unlock tables;
    

    连续插入会话会限制应用程序的吞吐量,因为会话正在排队。但这样可以避免死锁。

    我可以添加“锁表”吗在我的触发器中?或者只在我的代码中插入查询之前?!你应该在代码中插入查询之前执行。我认为如果在触发器中执行,要避免争用条件将为时已晚。触发器中的此构造如何-“选择max()…进行更新”然后释放锁?我认为你也不能这样做。释放锁会隐式提交事务,但你不能从触发器启动或提交事务。如果你在同一个脚本中进行5次插入,它们应该会起作用。一旦你在一个会话中锁定表,你就可以在同一个会话中写入表而不会出现问题。其他会话必须等待您的会话释放其锁。
    mysql> unlock tables;
    
    mysql> update foo set id = 2;
    ...
    Query OK, 1 row affected (3.50 sec)
    Rows matched: 1  Changed: 1  Warnings: 0