如何在给定时间后自动解锁Oracle中的表



我有一些代码可以连接到Oracle数据库,锁定表,对它执行一些操作并解锁它。
我想知道,如果我的程序在表被锁定时冻结,锁定会自动释放。

有没有任何方法可以设置Oracle,自动执行此操作?

例如,我想说这样一句话:"如果用户x在表y上保持了z秒以上的锁定,则回滚事务并释放表。"

如果这不可能,我还能做些什么来达到同样的结果吗?这是一个真正的问题,还是我只是偏执?

提前谢谢。

首先,锁定表不会阻止另一个会话针对数据发出SELECT语句。

在会话1中,如果我锁定表

SQL> lock table foo in exclusive mode;
Table(s) Locked.

然后我可以启动会话2并查询我想要的所有数据

SQL> select * from foo;
      COL1
----------
         1
         1

在Oracle中,写入程序不会阻止读取器,因此您永远无法阻止另一个会话查询表中的数据。

听起来您试图实现的是悲观锁定。在这种情况下,不锁定表,而是执行SELECT FOR UPDATE,锁定要处理的特定条目。只要所有其他会话也尝试执行SELECT FOR UPDATE(取决于Oracle版本,可能会添加SKIP LOCKED限定符和/或WAIT限定符)。这会锁定您正在处理的特定行,并允许第二个会话根据实现的具体情况选择不同的行或超时,或者发现没有行要处理。这并不涉及锁定桌子。

释放锁的唯一方法是让获取锁的会话释放锁(通常通过结束事务),或者让获取锁定的会话终止。如果客户端应用程序仍在运行,但没有采取任何措施来释放锁定或终止会话,则锁定将无限期保持。DBA需要显式地终止会话,让事务回滚并释放锁以使系统重新运行。如果客户端应用程序停止运行,或者至少停止响应(我仍然不清楚你正在讨论的确切失败场景),那么在数据库级别通过"SQLNET.EXPIRE_TIME"参数启用死连接检测(DCD)可能会导致数据库确定客户端无响应并自动终止会话,回滚事务并释放锁。

然而,如果有多个会话在处理数据,通常最好使用某种形式的乐观锁定。否则,您正在设计一个系统,该系统将不可避免地需要DBA紧急查找并终止会话,以便让业务用户重新工作,而且越忙,就需要越来越多的干预。这不是DBA喜欢做的事情,也不是业务用户喜欢抱怨的事情。一个简单的乐观锁定方案就像

  • 选择一个要处理的键,以及指示行最后更新时间的某种日期
  • 将状态列更新为"正在处理",以便其他会话不会尝试处理同一行
  • 处理申请中的条目
  • 处理完成后,使用在第一步中选择的键和时间更新数据。如果更新1行,则表明自您选择该数据以来,没有其他会话修改过该数据。如果更新0行,则说明自您选择数据以来,有其他会话修改了该数据

有了这种体系结构,查询数据库以查看正在处理的行相对容易,例如,如果客户端还没有完成,则可以在一段时间后将状态列设置回"未处理"。对于其他会话来说,选择不同的行进行处理是非常容易的。例如,如果应用程序冻结几个小时,然后恢复,这是相对安全的,因为它只是在处理完后发现其他会话已经重新处理了该行。

最新更新