Oracle死锁问题分析解决

死锁发生的情况一般是资源存在环形依赖。

Oracle上的死锁一般出现于“行级锁”的环形依赖情况下:

  1. 有记录A、B,事务T1、T2,现在T1、T2并发执行update(或delete)A+B
  2. 事务T1操作的顺序为A-B,正常情况下会先后锁住A和B
  3. 事务T2操作的顺序为B-A,正常情况下会先后锁住B和A
  4. T1、T2并发执行,T1锁住A 同时 T2锁住B;
  5. T1操作完A想要锁住B,但B已被T2锁住,T1等待中;T2操作完B想要锁住A,但A已被T1锁住,T2等待中;

由于T1、T2都在等待又都不释放,因此造成死锁。

当死锁越来越多的时候,数据库连接被耗尽,不再能接受新的连接;数据库服务器的CPU和内存也可能会不够用了……程序猿就悲剧了。


解决办法:

在事务开始时或开始前先对操作数据按统一规则排序。

例如:按A-B顺序排序,使得T1、T2操作的顺序都为A-B,假设T1、T2并发执行时T1锁住了A;则T2只能等待A的锁了,B就没有机会被T2锁住了;这样T1就可以顺利锁住B,并顺利执行;当T1执行完成,释放A、B,T2就可以继续执行了。


从线上死锁的情况来看,主要发生在以下两种场景:

  1. 在同一个事务中无序的update或delete多条记录,事务并发执行可能会有死锁。
  2. 没有事务,但执行单条update或delete SQL时,如果update或delete所影响的记录数大于1,也有可能出现死锁。

对于第1种场景可以使用前述的解决办法处理,即先排序后执行;

对于第2种场景的解决办法如下:

先用select查询出需要操作的记录主键,按主键排序,再通过主键一条一条迭代执行。

不过将一条语句变成多条语句执行会破坏原有的事务(JDBC默认事务:一条SQL语句即一个事务),无法保证操作的原子性了,这就需要将这些操作放入一个事务中。或者可以使用 in 语句将其改造成一条SQL,例如:update ... where id in ( 1,2,3,4... ) ...,这样效率会比多条SQL语句高一些,而且 in 是可以命中索引的。

你可能感兴趣的:(oracle,oracle,oracle,数据库,优化,死锁,解决)