mysql innodb 事务操作的表锁及行锁-Deadlock found when trying to get lock; try restarting transaction的优化

本文介绍了数据库中的锁机制,包括共享锁和排它锁的概念及应用。详细解释了行锁与表锁的区别,以及如何通过合理选择删除操作来减少死锁的发生,提高并发性能。

1.锁的类型

锁有共享锁(S)和排它锁(X)

以及隐性锁和显性锁。

如select * from xx for update

这样现性的增加了一个表锁在表之上。

而update和delete则会隐性的在表上或者行上增加一个锁。

2.行锁和表锁

(1)行锁

对记录的的锁定,如update和delete操作会加锁,这时关于这条记录的查询操作是不能进行的,需要等待;

(2)表锁

对表一级的锁定,所有对这个表的查询都将被挂起,直到事务完成。

3.删除操作增加锁的区别

如果要是批量删除某些记录,如果在高并发情况下,如果使用非主键和索引的字段进行删除,如用exist关键字的查询,则会将整个表进行了锁定。

这种情况下,好多的查询都处于等待的状态这样,性能自然不会高。

而如果使用主键索引的字段进行删除、如用游标进行删除,那么就是增加的行锁,锁定只是对行一级的锁定,并不影响对其他行的查询。


在更改了删除方式之后,Deadlock found when trying to get lock; try restarting transaction,这个错误有效的减少了。

这个错误是说,mysql发现了一个死锁,那么就重启这个事务,这样就解决了数据死锁的问题。

而且因为这个机制的存在,数据库用innodb引擎\4CORE\4G的条件下跑出40并发no thinking 的成绩,性能还是不错的。

<think>嗯,用户这次提出了MySQL并发Insert操作导致死的具体问题,错误信息很明确是"Deadlock found when trying to get lock; try restarting transaction"。从用户引用的资料来看,这个问题在MySQL高并发场景下相当常见。 用户引用了5个资料片段,都指向同一个典型现象:并发事务MySQL检测到死后自动回滚。特别是引用[3]展示了实际报错的SQL语句(DELETE操作),引用[5]甚至给出了事务日志片段,说明用户可能已经查看过部分日志。 结合这些引用和我的知识,需要从几个层面考虑解决方案: 首先是索引问题,很多死源于缺失必要索引,导致升级为。比如在user_id字段无索引时,即使删除特定user_id的记录,也可能定整个。 其次是事务设计问题,引用[1][2]都暗示事务范围过大容易引发资源竞争。需要检查是否所有操作都需要在同一个事务里,特别是混合insert/update/delete时。 然后是重试机制,引用[2][3]提到这是必要手段,因为MySQL检测机制本身就会要求重试。但要注意退避算法,简单的while循环可能雪上加霜。 最后是隔离级别,引用[4]提到RR隔离级别更容易出现gap冲突,而电商场景用RC往往更合适。 用户没有提供具体业务场景,但引用[3]的SQL涉及user_id条件删除,引用[5]是更新return_code字段,推测可能是订单类系统。这类系统尤其要注意热点账户问题,比如集中操作同一商家的退货单。 考虑到用户可能急需解决方案,应该优先给出可立即实施的建议:比如检查索引状态、调整事务范围这些见效快的操作。同时也要提供分析工具的使用方法,毕竟引用[5]显示用户能接触到事务日志,说明有排查权限。 需要提醒的是,死在并发场景不可能100%消除,重点在于降低频率和快速恢复。所以重试策略和报警设置也很重要,这在引用[2]的解决方案部分被着重强调过。 </think>以下是针对 MySQL 并发 Insert 操作触发死(`Deadlock found when trying to get lock; try restarting transaction`)的综合解决方案,结合引用文献和最佳实践: --- ### **一、根本原因分析** 死通常由**事务间循环等待资源**引发,常见于以下场景: 1. **索引缺失**:未对 `WHERE` 条件列建立索引,导致升级为(引用[3][4])。 2. **执顺序不一致**:事务 A 按 `id=1 → id=2` 顺序操作事务 B 按 `id=2 → id=1` 顺序操作,形成循环等待。 3. **Gap Lock 冲突**:在高并发 `INSERT` 时,事务竞争相邻记录间的间隙(Next-Key Lock)(引用[4][5])。 4. **长事务与大事务**:事务包含过多操作,持有时间过长(引用[1][3])。 --- ### **二、解决方案** #### 1. **优化索引设计** - **强制使用索引**:为 `WHERE`、`ORDER BY` 涉及的列添加索引,避免全扫描。 - **减少范围**:使用唯一索引或主键插入,缩小间隙范围(引用[4])。 ```sql ALTER TABLE `table_name` ADD INDEX `idx_user_id` (`user_id`); -- 引用[3]中缺失索引的案例 ``` #### 2. **调整事务逻辑** - **缩小事务范围**:将大事务拆分为小事务,减少持有时间(引用[1][3])。 - **固定操作顺序**:所有事务按相同顺序访问数据(如先操作 `id` 小的记录)。 - **避免热点更新**:如自增主键插入冲突,改用雪花算法等分布式 ID。 #### 3. **降低隔离级别** - 将隔离级别从默认的 `REPEATABLE READ` 改为 `READ COMMITTED`: ```sql SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` - **效果**:减少 Gap Lock 的使用(引用[4]),但需评估业务一致性要求。 #### 4. **重试机制** - 捕获死异常(错误码 `1213`)后自动重试(引用[2][3]): ```python max_retries = 3 for attempt in range(max_retries): try: execute_insert_transaction() # 执插入操作 break except MySQLdb.OperationalError as e: if e.args[0] == 1213: # 死错误码 sleep(0.1 * (2 ** attempt)) # 指数退避等待 else: raise e ``` #### 5. **监控与日志分析** - **查看死日志**:启用 `innodb_print_all_deadlocks`,记录到错误日志(引用[5]): ```sql SET GLOBAL innodb_print_all_deadlocks = ON; ``` - **分析死信息**:通过 `SHOW ENGINE INNODB STATUS` 定位冲突事务和 SQL 语句(引用[4][5])。 --- ### **三、预防措施** 1. **避免批量删除后立即插入**:如引用[3]中的 `DELETE ... user_id=?` 语句,在并发下易与插入冲突。 2. **使用乐观**:通过版本号控制并发写入,如: ```sql UPDATE table SET col=new_val, version=version+1 WHERE id=1 AND version=old_version; ``` 3. **限制并发线程数**:通过连接池(如 HikariCP)控制数据库访问并发度。 --- ### **死分析示例** 引用[5]的事务日志显示: ```log *** (1) TRANSACTION: UPDATE inc_t_store ... SET return_code='683901058240105_5' -- 事务1更新操作 *** (2) TRANSACTION: INSERT INTO inc_t_store ... -- 事务2插入操作 *** (2) HOLDS THE LOCK: RECORD LOCKS ... gap before record -- 持有间隙 *** (2) WAITING FOR THIS LOCK: RECORD LOCKS ... insert intention waiting -- 等待插入意向 ``` **结论**:事务 1 的更新阻塞了事务 2 的插入意向,需检查 `return_code` 索引或调整执顺序[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值