产生原因:
- 两个线程
- 不同方向
- 相同资源
只要上面3个碰在一起一定会出现死锁问题!
举个例子:转账
两个事务单元
事务单元一
第一步操作:Lock Bob
第二部操作:Lock Simth
事务单元二
第一步操作:Lock Simth
第二部操作:Lock Bob
他们俩都持有一把锁;
事务单元2想要Lock Bob的时候,他是进不到Bob那个锁上面的,于是事务单元2就等待了;
而事务单元1想要Lock Smith的时候,他也是进不到Smith的那个锁上面的,他也会在外面等待;
相互之间等待,而相互之间又维持了一个锁,这就是死锁产生的原因
死锁解决办法:
- 尽可能不死锁
如:尽可能降低隔离级别,因为死锁的核心主要就是事务之间相互等待产生的;
不加读锁自然而然就能减少死锁的可能;
这个一般对用户要求较高,所以一般数据库会提供两个主要的死锁检测的方法:第一种交碰撞检测;第二种叫等锁超时 - 碰撞检测
把事务单元和事务单元所维持的锁都记录下来,比如把事务单元1所有等待的锁,去申请锁之前先记录到内存里,当他锁住Bob的时候,再去锁住Smith的时候需要去申请另外一把锁,然后利用Smith在查看看这把锁申请的事务单元有哪些锁,发现事务单元2,然后去看事务单元2又是在申请哪些锁,会发现又回来了,于是在这种情况下,就认为在事务单元1中Lock Smith的时候发生了一个碰撞;于是解决了这个死锁问题,只要终止一边就可以了!
这种方式的效率一般来说是最高的;等锁超时效率稍微会低一点 - 等锁超时
也是一种比较常见的作法,我等待持有锁的时间,比如持有超过一分钟,我就认为这个锁可能有问题,超时了直接给你报错,但这种方式会带来一个问题;比如超长事务,这种死锁检测的方式会导致每一个死锁被发现都需要非常长的时间,有些时候是不能接受的,所以在主流的数据库中主要是使用碰撞检测;