在某些情况下由于占用的资源不能及时释放,而造成锁等待,也可称为锁冲突。锁等待会严重影响数据库性能和日常工作。例如,当一个会话修改表A的记录时,它会对该记录加锁,而此时如果另一个会话也来修改此记录,那么第二个会话将因得不到排他锁而一直等待,此时会出现执行SQL时数据库长时间没有响应的情况。直到第一个会话将事务提交,释放锁,第二个会话才能对数据进行操作。
【例13.3】 锁等待。
该示例将演示锁等待的现象,具体分为如下两个步骤。
①打开SQL∗Plus窗口,修改DEPARTMENTS表中DEPARTMENT_ID字段为280的记录。脚本如下:
此时虽然提示已更新,但事务并没有提交。接下来进行第二步操作。
②打开另一个SQL∗Plus窗口,同样修改DEPARTMENTS表中DEPARTMENT_ID字段为280的记录。脚本如下:
此时的执行效果不会提示已更新,而是一直等待,效果如图13.7所示。
图13.7 等待更新数据
此时的情况是因为第一个会话封锁了该记录,但事务没有结束,锁不会释放,而这时第二个会话也要修改同一条记录,但它却没有办法获得锁,所以只能等待。如果第一个会话修改数据的事务结束,那么第二个会话就会结束等待。及时地结束事务是解决等待情况发生的有效方法。
死锁的发生和锁等待不同,它是锁等待的一个特例,通常发生在两个或多个会话之间。假设一个会话想要修改两个资源对象,可以是表也可以是字段,修改这两个资源的操作在一个事务当中。当它修改第一个对象时需要对其锁定,然后等待第二个对象,这时如果另一个会话也需要修改这两个资源对象,并且已经获得并锁定了第二个对象,那么就会出现死锁,因为当前会话锁定了第一个对象等待第二个对象,而另一个会话锁定了第二个对象等待第一个对象。这样,两个会话都不能得到想要得到的对象,于是出现死锁。
【例13.4】 死锁的发生。
下面是演示死锁发生的示例。具体分为下述4个步骤。
①打开第一个SQL∗Plus窗口,创建第一个会话,执行如下脚本,修改DEPARTMENTS表中DEPARTMENT_ID字段为280的记录。脚本如下:
②打开第二个SQL∗Plus窗口,创建第二个会话,执行如下脚本,修改DEPARTMENTS表中DEPARTMENT_ID字段为290的记录。脚本如下:
到目前为止,第一个会话锁定了DEPARTMENT_ID字段为280的记录,第二个会话锁定了DEPARTMENT_ID字段为290的记录。
③第一个会话修改第二个会话已经修改的记录。执行脚本如下:
此时第一个会话将出现锁等待,因为它修改的对象已经被第二个会话锁定,效果如图13.8所示。
图13.8 第一个会话出现锁等待(www.daowen.com)
④第二个会话修改第一个会话已经修改的记录。执行脚本如下:
此时会出现死锁的情况。Oracle会自动检测死锁的情况,并释放一个冲突锁,并把消息传递给对方事务。此时在第一个会话窗口中会提示检测到死锁,如图13.9所示。
图13.9 死锁提示
此时Oracle会自动做出处理,并重新回到锁等待的情况。在出现锁等待的情况时应尽快找出错误原因并对其进行处理,以免影响数据库性能。在实际应用中出现此类情况大致有以下几种原因:
①用户没有良好的编程习惯,偶尔会忘记提交事务,导致长时间占用资源。
②操作的记录过多,而且操作过程中没有很好地对其分组。前面介绍过,对于数据量很大的操作,可以将其分成几组提交事务,这样可以避免长时间地占用资源。
③逻辑错误,两个会话都想得到已占有的资源。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。