7

我们使用 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"

(我们正在使用类型)。由于某种原因,该命令没有执行,并且数据库表被锁定。所有其他操作都在等待第一个线程完成,但是线程被杀死并且我们已经到达死胡同。

避免这种灾难性情景的最佳解决方案是什么?我可以在语句中设置超时,以便 100% 线程可以对“选择更新”进行操作,比如说最多 10 秒吗?换句话说,执行线程可以锁定数据库表/行,但不能超过预定时间。

这可能吗?

4

2 回答 2

4

有一个会话参数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 级别上,您将不得不处理此错误。

于 2016-12-02T12:04:17.567 回答
4

编辑:添加了Resource Manager,它可以施加更精确的限制,只关注那些阻止其他人的会话......

通过资源管理器:

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

您必须定义计划和与计划关联的用户组,必须指定与计划/组关联的策略,最后必须将用户附加到组。要了解如何执行此操作,您可以重用此示例 @support.oracle.com(此处发布似乎有点太长),但将 替换MAX_IDLE_TIMEMAX_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.

创建个人资料

如果用户超过CONNECT_TIMEIDLE_TIME会话资源限制,则数据库回滚当前事务并结束会话。当用户进程下一次发出调用时,数据库返回错误

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

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 不会返回被锁定的记录(因为ibre5041已经指出)。
  • 您可以向另一个会话(一种看门狗)发出信号,表明您的会话已启动查询,并在成功执行后提醒它完成。看门狗会话可以实现其“超时后终止会话”逻辑。您必须付出额外的复杂性,但可以将超时应用于该特定语句而不是会话。为此,请参阅ORACLE-BASE - DBMS_PIPE3.2 DBMS_ALERT:向用户广播警报,作者 Steven Feuerstein,1998 年

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

于 2016-12-09T09:46:53.503 回答