Oracle 12. occi c++ "select for update" 的最大持续时间

Oracle 12. Maximum duration for "select for update" for occi c++

我们正在使用 occi 以通过 C++ 进程访问 Oracle 12。其中一个操作必须保证客户端必须从数据库中选取最新的数据,并根据最新的值进行操作。语句是

std::string sqlStmt = "SELECT REF(a) FROM O_RECORD a WHERE G_ID= :1 AND P_STATUS IN (:2, :3) FOR UPDATE OF PL_STATUS"

(我们正在使用类型)。由于某种原因,这个命令没有通过,数据库 table 被锁定。所有其他操作都在等待第一个线程完成,但是线程被终止,我们已经到了死胡同。

避免这种灾难性情景的最佳解决方案是什么?我可以在语句中设置超时,以便 100% 线程可以在 "select for update" 上运行,比方说最多 10 秒吗?换句话说,执行线程可以锁定数据库 table/row 但不会超过预定时间。

这可能吗?

有会话参数 ddl_lock_timeout 但没有 dml_lock_timeout。所以你不能走这条路。所以要么你必须使用

SELECT REF(a) 
FROM O_RECORD a 
WHERE G_ID= :1 AND P_STATUS IN (:2, :3) 
FOR UPDATE OF PL_STATUS SKIP LOCKED

并修改应用逻辑。或者您可以实现自己的中断机制。简单地触发一个并行线程并在一段时间后执行 OCIBreak。它是有记录和支持的解决方案。调用 OCIBreak 是线程安全的。阻塞的SELECT .. FOR UPDATE语句将被释放,你会得到一个错误ORA-01013: user requested cancel of current operation

所以在 OCCI 级别你将不得不处理这个错误。

编辑:添加了资源管理器,它可以施加更精确的限制,只关注那些阻塞其他会话的会话...

通过 资源管理器:

资源管理器允许定义比配置文件可用的策略更复杂的策略,在您的情况下比后者更合适。

您必须定义计划和与该计划关联的用户组,必须指定与 plan/groups 关联的策略,最后必须将用户附加到组。要了解如何执行此操作,您可以重复使用此 example @support.oracle.com(它似乎有点太长,无法在此处发布),但将 MAX_IDLE_TIME 替换为 MAX_IDLE_BLOCKER_TIME

核心线是

dbms_resource_manager.create_plan_directive(
  plan => 'TEST_PLAN',
  group_or_subplan => 'my_limited_throttled_group',
  comment => 'Limit blocking idle time to 300 seconds',
  MAX_IDLE_BLOCKER_TIME => 300)
;

通过 配置文件:

您可以限制那些指定 IDLE_TIME.

的会话的不活动时间

CREATE PROFILE:

If a user exceeds the CONNECT_TIME or IDLE_TIME session resource limit, then the database rolls back the current transaction and ends the session. When the user process next issues a call, the database returns an error

为此,请指定一个具有最大空闲时间的配置文件,并将其仅应用于相关用户(这样您就不会影响所有用户或应用程序)

CREATE PROFILE o_record_consumer
  LIMIT IDLE_TIME 2; --2 minutes timeout

alter user the_record_consumer profile o_record_consumer;

缺点是此设置是会话范围的,因此如果同一个会话在其他操作过程中应该能够保持空闲状态,则无论如何都会强制执行此策略。

感兴趣...

也许您已经知道其他会话可能会以多种方式协调对同一记录的访问:

  • FOR UPDATE WAIT x; 如果将 WAIT x 子句附加到 select for update 语句,等待会话将在 "x" 秒后放弃等待。 (整数 "x" 必须在那里进行硬编码,例如值“3”;变量不会,至少在 Oracle 11gR2 中是这样)。
  • SKIP LOCKED; 如果将 SKIP LOCKED 子句附加到 select for update 语句,select 将不会 return 锁定的记录(如 已经指出了)。
  • 您可以向另一个会话(一种看门狗)发出信号,表明您的会话已准备好开始查询,并在成功执行后提醒它完成。看门狗会话可以实现其 "kill-the-session-after-timeout" 逻辑。您必须支付增加的复杂性,但可以获得将超时应用于该特定语句而不是会话的好处。为此,请参阅 ORACLE-BASE - DBMS_PIPE or 3.2 DBMS_ALERT: Broadcasting Alerts to Users, By Steven Feuerstein, 1998

最后,您可能正在尝试实现自制的队列基础结构。在这种情况下,请记住 Oracle 已经拥有自己的称为 Advanced Queue 的队列机制,您只需使用它们就可以事半功倍;参见 ORACLE-BASE - Oracle Advanced Queuing