PL / SQL函数中的INSERT语句

时间:2016-09-09 09:48:58

标签: oracle function plsql

我在PL / SQL中编写了一个函数,它调用带有一些参数的web服务,解析答案并返回一个值。它运作得很好。

但是,有时反应可能会很慢。由于参数通常在所有可能值的非常小的子集中,我有想法将答案缓存在表中。 该功能如下所示

CREATE OR REPLACE FUNCTION myfct(p1 IN VARCHAR2, p2 IN VARCHAR2)
RETURN VARCHAR2
IS
    cache_hit NUMBER ;
    res VARCHAR2(200) ;
BEGIN
    SELECT COUNT(*) INTO cache_hit FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;

    IF( cache_hit = 1 )
    THEN
        SELECT MYCACHE.result INTO res FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;

        RETURN res ;
    END IF ;

    -- complex operations 
    res := p1 || p2 ;


    INSERT INTO MYCACHE(param1, param2, result) VALUES(p1, p2, res) ;

    RETURN res ;
END ;

当我尝试这个功能时:

SELECT myfct('ABC', 'DEF') FROM DUAL ;

我收到了错误:

ORA-14551: cannot perform a DML operation inside a query 

尝试将DML部分包装在一个过程中并在函数中调用此过程无济于事

我找到了PRAGMA AUTONOMOUS_TRANSACTION和COMMIT的解决方法:

CREATE OR REPLACE FUNCTION myfct(p1 IN VARCHAR2, p2 IN VARCHAR2)
RETURN VARCHAR2
IS
    PRAGMA AUTONOMOUS_TRANSACTION;
    cache_hit NUMBER ;
    res VARCHAR2(200) ;
BEGIN
    SELECT COUNT(*) INTO cache_hit FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;

    IF( cache_hit = 1 )
    THEN
        SELECT MYCACHE.result INTO res FROM MYCACHE WHERE param1 = p1 AND param2 = p2 ;

        RETURN res ;
    END IF ;

    -- complex operations 
    res := p1 || p2 ;


    INSERT INTO MYCACHE(param1, param2, result) VALUES(p1, p2, res) ;

    COMMIT ;
    RETURN res ;
END ;

但我不知道这是不是一个好主意。提到这种解决方法的人说这可能很危险,但没有说明原因。

我的功能是PRAGMA AUTONOMOUS_TRANSACTION的一个好用例,还是有更好更安全的方式来做我想要的?

3 个答案:

答案 0 :(得分:3)

可以从SQL上下文调用哪种PL / SQL函数存在限制。不要在SQL上下文中调用PL / SQL函数,而是在PL / SQL上下文中调用,所有内容都应该是好的:

declare
  v_foo constant varchar2(32767) := myfct('foo', 'bar');
begin
  dbmsn_output.put_line(v_foo);
end;

但是,在实现自己的缓存之前,请考虑使用Oracle原生PL/SQL Function Result Cache - 功能:

  

PL / SQL函数结果缓存机制提供了一种语言支持和系统管理的方法,用于在共享全局区域(SGA)中缓存PL / SQL函数的结果,该区域可用于运行应用程序的每个会话。缓存机制既高效又易于使用,减轻了设计和开发自己的缓存和缓存管理策略的负担。

     

调用结果缓存函数时,系统会检查缓存。如果高速缓存包含先前调用具有相同参数值的函数的结果,则系统将高速缓存的结果返回给调用者,并且不重新执行函数体。如果缓存不包含结果,系统将运行函数体并将结果(对于这些参数值)添加到缓存中,然后再将控制权返回给调用者。

答案 1 :(得分:0)

按照惯例和良好的软件设计,函数不应该对数据库进行更改,只应返回值。请改用程序。这就是为什么在PLSQL中只有像C中那样的函数。但是,这主要被许多人认为是一种风格。但我强烈建议你将他们的用法分开。

答案 2 :(得分:0)

只需在匿名块中调用该函数即可。不要选择它。 像这样

Declare
V_result varchar2(20);
Begin
V_result := myfct('ABC', 'DEF');
DBMS_OUTPUT.PUT_LINE(V_RESULT);
End;