【问题标题】:DML inside a function call函数调用中的 DML
【发布时间】:2017-12-18 10:17:41
【问题描述】:

我有一个旧的客户端软件,它连接了一个用于持久性的 oracle 数据库。作为接口,客户端软件只允许调用函数和过程。我几乎可以完全访问数据库,也就是说,我可以定义函数和过程。由于接口的关系,只有函数可以返回值,我不能使用过程的OUT参数选项。

现在我只想从表中读取一个值:

SELECT value FROM myTable WHERE id = 42;

然后增加值:

UPDATE myTable SET value = value + 1 WHERE id = 42;

我可以为 select 语句使用一个函数,为更新使用一个过程,并依次调用这两者。这里的问题是客户端不存在事务。因此,在 select 和 update 之间,另一个线程可能会得到错误的值。

所以我的问题是,如何在不使用事务的情况下在事务中同时使用两个调用...

尝试过的方法:

  • 使用匿名 PL/SQL 块 -> 客户端不支持该语法。
  • 将两个调用放在一个函数中 -> 选择语句中不允许使用 DML。
  • PRAGMA AUTONOMOUS_TRANSACTION -> 听说是个坏东西,不应该用。

【问题讨论】:

  • Functions 旨在没有有副作用。如果你想改变数据库的状态,那么你需要使用Procedure
  • 如果你想要一个简单的counter,并且在这种情况下没有其他事情发生,你可以考虑CREATE SEQUENCE?
  • 如果我使用过程(并且不能使用OUT),我需要两个不是线程保存的数据库调用。
  • 那么你需要像SEQUENCE 这样的东西(如果你只有一个柜台,而不是一桌满满的柜台),或者有人需要修复你的软件架构。您已经列出了所有您不能使用的东西(事务、过程等),因此切断了数据库做您想做的事情的能力。如果您无法使用应使用的工具,请修复导致您无法使用正确工具的问题。
  • 没有AFTER SELECT触发器这样的东西。

标签: sql oracle plsql stored-functions


【解决方案1】:

可以在函数内部执行 DML,如下所示,但我强调 - 注意其他 cmets。考虑使用序列(甚至多个序列),因为在函数内部执行 DML 通常是一个坏主意,因为函数调用(如果从 SQL 调用)的执行次数不是确定性的。此外,如果大量使用,还会存在可扩展性问题。在多用户环境中,您需要处理锁定/序列化,否则您将在多个会话中返回 same 整数值。

所以...毕竟,你仍然想走这条路:-(

SQL> create table t ( x int );

Table created.

SQL> insert into t values (0);

1 row created.

SQL>
SQL> create or replace
  2  function f return int  is
  3    pragma autonomous_transaction;
  4    retval int;
  5  begin
  6    update t
  7    set x = x + 1
  8    returning x into retval;
  9    commit;
 10    return retval;
 11  end;
 12  /

Function created.

SQL>
SQL> select f from dual;

         F
----------
         1

1 row selected.

SQL> select * from t;

         X
----------
         1

1 row selected.

SQL> select f from dual;

         F
----------
         2

1 row selected.

SQL> select * from t;

         X
----------
         2

1 row selected.

SQL> select f from dual;

         F
----------
         3

1 row selected.

SQL> select * from t;

         X
----------
         3

1 row selected.

【讨论】:

  • 感谢您的回答。我知道你提出的解决方案,以及它的问题。因此,我很可能会放弃一致性并执行读取功能和更新过程。两个线程交错执行此工作流的机会非常低,我可能会冒险。
猜你喜欢
  • 2016-09-28
  • 2015-12-19
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
  • 2021-06-28
  • 1970-01-01
  • 1970-01-01
  • 2015-01-16
相关资源
最近更新 更多