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

时间:2012-01-24 20:01:27

标签: database oracle session locking

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

有没有办法设置Oracle,自动执行此操作?

例如,我正在考虑一些事情会说“如果用户x在表y上保持锁定超过z秒,则回滚事务并释放表。”

如果不可能,我还能做些什么来达到相同的效果吗?这甚至是一个实际问题还是我只是偏执狂?

提前致谢。

1 个答案:

答案 0 :(得分:11)

首先,锁定表不会阻止另一个会话针对数据发出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' parameter启用死连接检测(DCD)数据库级别将导致数据库确定客户端无响应并自动终止会话,回滚事务并释放锁定。

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

  • 选择要处理的密钥以及指示上次更新行的某种日期。
  • 将状态列更新为“处理”,以便其他会话不会尝试处理同一行。
  • 处理申请中的条目
  • 完成处理后,使用您在第一步中选择的键和时间更新数据。如果您更新了1行,则您知道自从您选择它以来没有其他会话修改过相关数据。如果更新0行,则表示您选择了其他会话已修改数据。

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