不是吧不是吧 开发这么多年你不会还没经历过死锁吧?

本文通过一个真实的案例介绍了数据库死锁的发生,分析了死锁产生的原因,主要是由于并发操作和next-key锁机制。同时,提出了两种避免死锁的方法:设置事务锁等待超时和开启主动死锁检测。最后,建议通过业务优化,如设置唯一索引来预防死锁。
摘要由CSDN通过智能技术生成

大家好,我是小林。

说个很早之前自己遇到过数据库死锁的问题。

有个业务主要逻辑就是新增订单、修改订单、查询订单等操作。然后因为订单是不能重复的,所以当时在新增订单的时候做了幂等性校验,做法就是在新增订单记录之前,先通过 select ... for update 语句查询订单是否存在,如果不存在才插入订单记录。

而正是因为这样的操作,当业务量很大的时候,就可能会出现死锁。

接下来跟大家聊下为什么会发生死锁,以及怎么避免死锁

死锁的发生

本次案例使用存储引擎 Innodb,隔离级别不可重复读(RR)。

接下来,我用实战的方式来带大家看看死锁是怎么发生的。

我建了一张订单表,其中 id 字段为主键索引,order_no 字段普通索引,也就是非唯一索引:

CREATE TABLE `t_order` (
  `id` int NOT NULL AUTO_INCREMENT,
  `order_no` int DEFAULT NULL,
  `create_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_order` (`order_no`) USING BTREE
) ENGINE=InnoDB ;

然后,先 t_order 表里现在已经有了 6 条记录:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提到的情况是可能发生的,如果在等待`synchronized`锁的过程中线程被中断,并且异常不会解除对锁的持有,那么可能会导致死锁。 一个典型的死锁场景是,线程A持有锁A并等待获取锁B,同时线程B持有锁B并等待获取锁A。如果线程A在等待锁B的过程中被中断,但并有解除对锁A的持有,那么线程B将永远无法获取到锁A,导致死锁。 为了避免这种情况,我们可以在捕获到`InterruptedException`异常后,显式地释放掉已经持有的锁。在`finally`块中释放锁可以确保无论是否发生异常,都能够正确释放锁资源,防止死锁的发生。 例如,可以使用以下方式来处理`InterruptedException`异常并释放锁: ```java synchronized (lock) { try { // 等待获取锁 while (!condition) { lock.wait(); } // 执行同步代码块 // ... } catch (InterruptedException e) { // 捕获InterruptedException异常 // 释放锁 lock.notifyAll(); Thread.currentThread().interrupt(); // 重新中断当前线程 } } ``` 在上述代码中,当捕获到`InterruptedException`异常时,我们通过调用`lock.notifyAll()`来唤醒其他等待该锁的线程,并使用`Thread.currentThread().interrupt()`重新中断当前线程,以便外部代码能够正确处理中断事件。 总之,为了避免死锁,当线程在等待`synchronized`锁的过程中发生`InterruptedException`异常时,我们应该显式地释放已经持有的锁,并进行适当的中断处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值