3

我目前有一个 INSERT TRIGGER,它在 Oracle 10g 中运行一个自定义函数,该函数生成一个时髦的字母数字代码,用作插入的一部分。

我真的需要确保函数(甚至触发器)是线程安全的,这样如果两个用户同时激活触发器,触发器中使用的函数不会为两个用户返回相同的代码。

触发器中的流程如下:

开始

  1. 根据业务逻辑判断是否需要继续
  2. 运行自定义函数以获取新代码
  3. 使用返回的代码作为插入到不同的表中

结尾

主要问题是,如果在第 2 步运行时,一个单独的线程触发触发器,该触发器也进入第 2 步,并返回与第一个线程相同的代码。(我知道这是一个非常紧张的情况,但我们需要处理它)。

我想到了两种主要的方法:

目前我想到的目前最好的方法是在触发器一开始就以“独占模式”锁定触发器中使用的表,并且指定锁的NOWAIT属性。这样,触发器的每个后续激活都会“停止并等待”锁可用,因此等待其他线程完成触发器。

我很想锁定表任何拒绝读取表,但我似乎可以找到如何在 Oracle 中执行此操作。

我的想法并不理想,但应该可行,但是我很想听听任何可能对此有更好想法的人!

非常感谢您提供的任何帮助。

干杯,马克

4

3 回答 3

5

无需在这里计算排他性。Oracle 通过管理您的事务来做到这一点。

关键是您的“自定义函数”的每次调用都需要返回一个唯一的代码。

这意味着不使用系统日期/时间,而是使用其他东西来确保唯一性。

我推荐这个:

select sys_guid() from dual;

用来加盐sys_guid()你的功能,一切都应该在触发地里。

只是请不要尝试使用此值更新不同的表,否则您将需要处理变异表等。

编辑:显然,正如其他几个人提到的那样,在触发器中使用序列来播种您的函数是另一个很好的建议,因为 Oracle 强制执行唯一性。使用它作为种子虽然可能会产生可预测的结果,所以如果“自定义功能”是密码重置或类似的东西,请小心。

于 2008-12-15T23:51:46.740 回答
1

一种解决方案是使用 Oracle 序列提供给生成唯一字符串的自定义代码。Oracle 正是出于这个原因提供了序列——因此生成唯一 ID 的方法是线程安全的。在此处查找Oracle 9i(我使用的版本)的文档。

于 2008-12-16T04:15:54.693 回答
1

“你根本不需要知道它是什么,它只是函数生成的代码”它必须是基于时间的,因为我们需要知道其他任何东西才能给出适当的答案。不确定是否影响您的吞吐量。您可以将 DBMS_LOCK.REQUEST 视为 1a,将 DBMS_LOCK.SLEEP 视为 2a,将 DBMS_LOCK.RELEASE 视为 2b。这可以确保每个锁都保持一秒钟,以便在任何一秒钟内只能发生一次插入。

如果它是基于序列的 Oracle 确保您不会两次获得相同的序列

如果它取决于会话/包状态(例如,在会话中递增),则会话一次只能发生一个插入(尽管它可能是多行插入...选择甚至是多表插入) .

如果它依赖于数据库状态(即函数执行查询),您需要考虑事务,而不是语句。您仍然可以使用 DBMS_LOCK,但您需要在提交后手动释放锁,以确保等待会话确实等到新数据提交并可见。

于 2008-12-16T02:07:51.863 回答