当两个应用程序彼此锁定对方所需的数据时就发生了死锁,这将导致两个应用程序都无法继续执行的情形。
例如,在下图中,有两个应用程序正在同时运行:应用程序 A 和应用程序 B。应用程序 A 的第一个步骤是更新表 1 的第一行,第二个步骤是更新表 2 的第二行。应用程序 B 首先更新表 2 的第二行,然后更新表 1 的第一行。在某个时间点 T1,应用程序 A 正在执行它的第一个步骤,锁定表 1 的第一行以更新此行。同时,应用程序 B 锁定表 2 的第二行以进行更新。在 T2,应用程序 A 尝试执行下一个步骤并请求锁定表 2 中的第二行以便进行更新。但是,同时应用程序 B 正在尝试锁定并更新表 1 中的第一行。由于应用程序 A 要等到它完成表 2 中第二行的更新后才释放对表 1 的第一行的锁定,而应用程序 B 要等待它锁定并更新表 1 的第一行后才释放对表 2 的第二行的锁定,这样就产生了死锁。应用程序会永远等待下去,直到“另一个”应用程序释放挂起数据上的锁定为止。
图 1. 应用程序之间的死锁因为应用程序不会自动释放它们所需的数据的锁定,死锁检测器过程是中断死锁并允许应用程序进程继续所必需的。顾名思义,死锁检测器监视关于等待锁定的代理程序的信息,并在 dlchktime 配置参数所指定的时间间隔苏醒。
如果它发现死锁,那么死锁检测器任意选择一个已死锁的进程作为牺牲进程来回滚。牺牲进程被唤醒,并将 SQLCODE -911(SQLSTATE 40001)返回到调用应用程序,原因码为 2。数据库管理器自动回滚所选进程中未落实的事务。当回滚完成时,释放属于牺牲进程的锁定,而该死锁涉及的其他进程可以继续进行。
要确保良好的性能,为死锁检测器选择适当的时间间隔。过短的时间间隔导致不必要的开销,而太长的时间间隔使死锁将进程延迟一段不可接受的时间。例如,5 分钟的唤醒时间间隔使死锁几乎存在 5 分钟,这对于短事务处理来说看起来可是长时间。在解决死锁时的可能延迟与检测它们的开销两者之间进行平衡非常重要。
注: 在分区数据库环境中,dlchktime 配置参数时间间隔仅在目录节点上适用。如果在分区数据库环境中检测到大量的死锁,增大 dlchktime 参数的值以解决锁定等待和通信等待。 在分区数据库中,每个数据库分区将锁定图发送到包含系统目录视图的数据库分区。在此数据库分区上进行全局死锁检测。在创建数据库的同时,会创建详细死锁事件监视器。同其他监视器一样,这个事件监视器将造成一些开销。
要限制此事件监视器消耗的磁盘空间量,当它达到其输出文件的最大数目时,该事件监视器就取消激活,并且会有一条消息写入管理通知日志。将不再需要的输出文件除去即可在下次激活数据库时重新激活事件监视器。
如果不需要详细死锁事件监视器,那么可使用以下命令删除事件监视器:
DROP EVENT MONITOR db2detaildeadlock在应用程序访问昵称的联合系统环境中,由于数据源处发生死锁而可能无法获取应用程序请求的数据。当发生这种情况时,DB2® 依靠数据源的死锁处理工具。如果在多个数据源之间发生死锁,那么 DB2 依靠数据源超时机制解开死锁。
要记录有关死锁的更多信息,将数据库管理器配置参数 diaglevel 设置为 4。记录的信息包括已锁定的对象、锁定方式以及挂起有锁定的应用程序。还可能会记录当前动态 SQL 和 XQuery 语句或静态程序包名称。仅在 diaglevel 4 记录动态 SQL 和 XQuery 语句。
缺省死锁事件监视器在创建数据库时,缺省情况下将创建并激活一个称为 DB2DETAILDEADLOCK 的死锁事件监视器。激活数据库时,会自动启动该死锁事件监视器。当此监视器处于活动状态时,首次发生死锁时就会收集诊断信息,并允许调查发生死锁的原因,而不需要再现当时的情况。信息将写入目标输出文件。
要限制此事件监视器消耗的磁盘空间量,当它达到其输出文件的最大数目时,该事件监视器就取消激活,并且会有一条消息写入管理通知日志。将不再需要的输出文件除去即可在下次激活数据库时重新激活事件监视器。
如果不想负担与详细死锁事件监视器相关联的开销,那么应该首先取消激活该事件监视器,然后使用下列命令删除该事件监视器:db2 set event monitor db2detaildeadlock state 0db2 drop event monitor db2detaildeadlock但是,如果要在发生死锁时收集诊断信息,那么应该保留此监视器。