mysql死锁,如何产生?如何发现?如何处理?

1 产生死锁 就是资源互斥 例子如下

好的,请参考以下 SQL 语句来创建 base_account_item 表和向表中插入一些数据:

CREATE TABLE base_account_item (
    id INT(11) NOT NULL,
    account_item_name VARCHAR(50) NOT NULL,
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO base_account_item (id, account_item_name) VALUES (1, '公司应收本金1');
INSERT INTO base_account_item (id, account_item_name) VALUES (2, '公司应收本金2');

这些 SQL 语句将创建一个名为 base_account_item 的表,其中包含两列:id 和 account_item_name。id 列被指定为主键,用于确保表中每行的唯一性,而 account_item_name 列包含基本帐户名称。然后,使用 INSERT 语句向表中插入两条示例数据。

接下来,您可以使用以下 SQL 语句来尝试以两个不同的连接模拟锁定和死锁问题:

# 连接1
START TRANSACTION;
SELECT * FROM base_account_item WHERE id = 1 FOR UPDATE;
-- 不提交或回滚,保持连接开启

# 连接2
START TRANSACTION;
SELECT * FROM base_account_item WHERE id = 2 FOR UPDATE;
-- 等待连接1释放锁

# 连接1(另一个终端或连接)
SELECT * FROM base_account_item WHERE id = 2 FOR UPDATE;
-- 此时发生死锁,连接1无法释放锁并等待连接2来释放锁

在这个例子当中,我们创建了两个事务连接模拟行锁死锁的情况。首先,使用连接1执行 SELECT * FROM base_account_item WHERE id = 1 FOR UPDATE; 语句锁定 ID 为 1 的行。然后,使用连接2执行 SELECT * FROM base_account_item WHERE id = 2 FOR UPDATE; 语句,尝试锁定 ID 为 2 的行,但是由于连接1已经锁定了 ID 为 1 的行,所以连接2 被阻塞等待连接1释放锁。最后,在连接1中再次执行 SELECT * FROM base_account_item WHERE id = 2 FOR UPDATE;,由于连接2占用了对 ID 为 2 的行的锁定,因此连接1发生死锁,无法释放 ID 为 1 的行的锁。

请注意,这仅是一个模拟死锁问题的例子,请不要在生产环境中执行此示例 SQL 语句。

2 如何发现

  -- 1、查看正在进行中的事务
SELECT * FROM information_schema.INNODB_TRX;
  -- 2、查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
  -- 3、查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
  -- 4、查询是否锁表
SHOW OPEN TABLES where In_use > 0;
在发生死锁时,这几种方式都可以查询到和当前死锁相关的信息
  -- 5、查看最近死锁的日志
show engine innodb status;

  -- 6、查看当前数据库的线程情况
SHOW FULL PROCESSLIST;
  -- 7、杀掉死锁对应的进程 id
kill id

-- 8 查看最后一次死锁情况- 注意复制出来=====里面的内容,里面有好多
show engine innodb status

--9 
/etc/my.cnf 文件中修改或增加配置,注意增加的位置[mysqld] 的下面,否则无效;
innodb_print_all_deadlocks = ON
error日志的路径可以通过如下sql查看:
SHOW VARIABLES LIKE 'log_error';
这样就可以通过错误日志分析排查mysql死锁

  注:5中可能不显示详细的死锁日志,打开死锁监控日志见:innodb锁-开启锁监控功能

① 下面对 innodb_trx 表的每个字段进行解释:

trx_id:事务ID。
trx_state:事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。
trx_started:事务开始时间。
trx_requested_lock_id:事务当前正在等待锁的标识,可以和 INNODB_LOCKS 表 JOIN 以得到更多详细信息。
trx_wait_started:事务开始等待的时间。
trx_weight:事务的权重。
trx_mysql_thread_id:事务线程 ID,可以和 PROCESSLIST 表 JOIN。
trx_query:事务正在执行的 SQL 语句。
trx_operation_state:事务当前操作状态。
trx_tables_in_use:当前事务执行的 SQL 中使用的表的个数。
trx_tables_locked:当前执行 SQL 的行锁数量。
trx_lock_structs:事务保留的锁数量。
trx_lock_memory_bytes:事务锁住的内存大小,单位为 BYTES。
trx_rows_locked:事务锁住的记录数。包含标记为 DELETED,并且已经保存到磁盘但对事务不可见的行。
trx_rows_modified:事务更改的行数。
trx_concurrency_tickets:事务并发票数。
trx_isolation_level:当前事务的隔离级别。
trx_unique_checks:是否打开唯一性检查的标识。
trx_foreign_key_checks:是否打开外键检查的标识。
trx_last_foreign_key_error:最后一次的外键错误信息。
trx_adaptive_hash_latched:自适应散列索引是否被当前事务锁住的标识。
trx_adaptive_hash_timeout:是否立刻放弃为自适应散列索引搜索 LATCH 的标识。

 ② 下面对 innodb_locks 表的每个字段进行解释:

lock_id:锁 ID。
lock_trx_id:拥有锁的事务 ID。可以和 INNODB_TRX 表 JOIN 得到事务的详细信息。
lock_mode:锁的模式。有如下锁类型:行级锁包括:S、X、IS、IX,分别代表:共享锁、排它锁、意向共享锁、意向排它锁。表级锁包括:S_GAP、X_GAP、IS_GAP、IX_GAP 和 AUTO_INC,分别代表共享间隙锁、排它间隙锁、意向共享间隙锁、意向排它间隙锁和自动递增锁。
lock_type:锁的类型。RECORD 代表行级锁,TABLE 代表表级锁。
lock_table:被锁定的或者包含锁定记录的表的名称。
lock_index:当 LOCK_TYPE=’RECORD’ 时,表示索引的名称;否则为 NULL。
lock_space:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的表空间 ID;否则为 NULL。
lock_page:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的页号;否则为 NULL。
lock_rec:当 LOCK_TYPE=’RECORD’ 时,表示一堆页面中锁定行的数量,亦即被锁定的记录号;否则为 NULL。
lock_data:当 LOCK_TYPE=’RECORD’ 时,表示锁定行的主键;否则为NULL。

③ 下面对 innodb_lock_waits 表的每个字段进行解释:

requesting_trx_id:请求事务的 ID。
requested_lock_id:事务所等待的锁定的 ID。可以和 INNODB_LOCKS 表 JOIN。
blocking_trx_id:阻塞事务的 ID。
blocking_lock_id:某一事务的锁的 ID,该事务阻塞了另一事务的运行。可以和 INNODB_LOCKS 表 JOIN。

3 如何处理

1 先kill掉死锁事务中的一个。

2 分析日志 修改事务 避免死锁,例如顺序执行,加分布式锁,或者更改锁的顺序。

3 写事务的时候注意,更新不要涉及多个表,如果涉及要确定顺序。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值