函数中的DML语句的执行问题--自治事务

问题:写一个函数,函数中要更新数据库中的某个字段,函数在使用时格式是:select funcName() from dual; 那么此函数中如果含有update语句

函数:

create or replace function CalABGrpRearBounty()

return number is Result number;

begin

    update larearrelation set rearcommflag = 2 where rearcommflag = 1;

     commit;

end;

报:ORA-14551,不能在查询语句中执行dml语句

开始以为函数本身有问题,其实不然,是因为select funcName() from dual; 这个语句的问题


 

 

解决:函数中使用自治事务

            自治事务实现的功能是自治事务的提交或回滚不影响当前的事务。同时自治事务也是看不到当前会话所做的未提交的修改的。

create or replace function CalABGrpRearBounty(tAgentCode laagent.agentcode%type,
                                              tAgentGrade latree.agentgrade%type
                                              )
return number is pragma autonomous_transaction;

mResult number;
mAgentCode laagent.agentcode%type;
mFYCMin lawageradix.fycmin%type; -- 非本人推荐的奖金数量
mFYCMax lawageradix.fycmax%type; -- 本人推荐的奖金数量
mRecommendCount number;          -- 推荐次数
mRearCommFlag number;           

begin
mResult := 0;
     -- 查询育成奖金标准
     select FYCMin into mFYCMin from lawageradix where agentgrade = tAgentGrade and wagecode = 'WA0009' and branchtype = 2;

     if(mFYCMin is not null and mFYCMin > 0)
     then
         begin
              select FYCMax into mFYCMax from lawageradix where agentgrade = tAgentGrade and wagecode = 'WA0009' and branchtype = 2;

              -- 查询被育成人,存在育成关系,且未提佣,且计算日期在育成止期后
              -- rearcommflag=1:未进行佣金计算;rearcommflag=2:已进行过佣金计算;rearcommflag=3:已审核。            
              declare cursor rearListCursor is
              select agentcode from larearrelation where rearagentcode = tAgentCode and rearflag = 1 and (rearcommflag = 1 or rearcommflag = 2);
              begin
                   open rearListCursor;
                   loop
                       fetch rearListCursor into mAgentCode;
                       exit when rearListCursor%notfound;

                       -- 查询育成人是否推荐人
                       select count(*) into mRecommendCount from larecomrelation where agentcode = mAgentCode and recomagentcode = tAgentCode
                                                            and recomflag = 1;
                       if(mRecommendCount = 1)
                       then
                            mResult := mResult + mFYCMax;
                       else
                            mResult := mResult + mFYCMin;
                       end if;

                       -- 更新rearcommflag=2,表示已计算过佣金
                       select rearcommflag into mRearCommFlag from larearrelation where rearagentcode = tAgentCode and agentcode = mAgentCode and rearflag = 1;
                       if(mRearCommFlag = 1)
                       then
                           begin
                                update larearrelation set rearcommflag = 2 where rearcommflag = 1 and rearagentcode = tAgentCode and agentcode = mAgentCode and rearflag = 1 ;
                                commit;
                           end;
                       end if;
                      
                   end loop;
                   close rearListCursor;
              end;
         end;
     end if;
return(mResult);
end;


以下摘自:作者: 杨廷琨,  出处:blog, 责任编辑: 王晓晨,  2008-08-04 09:31

http://database.ctocio.com.cn/tips/254/8246254.shtml

 

这两天看了11g的CONCEPT文档的事务部分,发现自治事务还有一些以前没有注意到的地方,这里简单总结一下。

  这一篇简单描述一下自治事务可以使用的位置。

  自治事务可以使用在以下的位置:

  存储过程和函数;

  本地过程和函数;

  包;

  对象方法;

  匿名块的最顶层。

  其中过程、函数和包中使用自治事务很常见,大部分自治事务的情况都属于这种情况。由于对象相对使用的比较少,所以对象方法中的自治事务也是比较少见的,不过由于对象中的方法和包中的存储过程、函数十分相似,所以这种情况也是情理之中的。

  剩下的两种情况,是以前所不了解的。从来没有想过对于本地过程和函数也是可以定义为自治事务的,不过本地过程定义为自治事务是十分方便的功能,使得过程中需要用到自治事务的功能时,不必再额外定义一个自治事务的存储过程,只需要在当前的过程中定义一个自治的本地过程就可以了。

  一个简单的例子如下:

SQL> CREATE TABLE T_AUTO_TRANS (ID NUMBER, NAME VARCHAR2(30));

  表已创建。 

SQL> CREATE TABLE T_LOG (ID NUMBER, NAME VARCHAR2(30));

  表已创建。

  下面建立一个LOCAL PROCEDURE的自治事务的例子:

SQL> DECLARE
  2 PRAGMA AUTONOMOUS_TRANSACTION;
  3 BEGIN
  4 INSERT INTO T_LOG VALUES (1, 'AUTONOMOUS_TRANSACTION');
  5 COMMIT;
  6 END;
  7 /

  PL/SQL 过程已成功完成。

SQL> SELECT * FROM T_AUTO_TRANS;
  ID NAME
  ---------- ------------------------------
  1 TEST
  SQL> SELECT * FROM T_LOG;
  ID NAME
  ---------- ------------------------------
  1 AUTONOMOUS_TRANSACTION
  1 AUTONOMOUS_TRANSACTION
  SQL> ROLLBACK;

  回退已完成。

SQL> SELECT * FROM T_AUTO_TRANS;
  未选定行

SQL> SELECT * FROM T_LOG;
  ID NAME
  ---------- ------------------------------
  1 AUTONOMOUS_TRANSACTION
  1 AUTONOMOUS_TRANSACTION

  这种情况的意义没有本地过程的大,不过对于编写包含大量的SQL和PL/SQL的sql文件还是有不少帮助的。

 Oracle 11g自治事务更像是在单独的会话中执行,它的事务状态不会影响当前的事务,它也不会看到当前事务没有提交的修改。


<script language=Javascript> </script>

小议Oracle 11g的自治事务(一)

小议Oracle 11g的自治事务(二)

   自治事务实现的功能是自治事务的提交或回滚不影响当前的事务。同时自治事务也是看不到当前会话所做的未提交的修改的。 

SQL> TRUNCATE TABLE T_AUTO_TRANS;

  表被截断。

SQL> CREATE OR REPLACE PROCEDURE P_TEST AS
  2 BEGIN
  3 INSERT INTO T_AUTO_TRANS VALUES (2, 'TEST');
  4 FOR I IN (SELECT COUNT(*) CNT FROM T_AUTO_TRANS) LOOP
  5 DBMS_OUTPUT.PUT_LINE('P_TEST:' || I.CNT);
  6 END LOOP;
  7 END;
  8 /

  过程已创建。 

SQL> CREATE OR REPLACE PROCEDURE P_TEST_AUTO AS
  2 PRAGMA AUTONOMOUS_TRANSACTION;
  3 BEGIN
  4 INSERT INTO T_AUTO_TRANS VALUES (2, 'TEST');
  5 FOR I IN (SELECT COUNT(*) CNT FROM T_AUTO_TRANS) LOOP
  6 DBMS_OUTPUT.PUT_LINE('P_TEST_AUTO:' || I.CNT);
  7 END LOOP;
  8 COMMIT;
  9 END;
  10 /

  过程已创建。

SQL> INSERT INTO T_AUTO_TRANS VALUES (1, 'TEST');

  已创建 1 行。 

SQL> SET SERVEROUT ON
  SQL> EXEC P_TEST
  P_TEST:2

  PL/SQL 过程已成功完成。

SQL> EXEC P_TEST_AUTO
  P_TEST_AUTO:1

  PL/SQL 过程已成功完成。

  可以看到,对于自治事务是看不到当前会话所作的未提交的修改的。

SQL> EXEC P_TEST
  P_TEST:4

  PL/SQL 过程已成功完成。

  而对于当前会话,由于自治事务的操作已经提交,因此之后的查询是可以看到自治事务所进行的修改的。

  自治事务看不到当前会话的修改,那么自治事务调用的过程是否能看到自治事务的修改呢: 

SQL> TRUNCATE TABLE T_AUTO_TRANS;

  表被截断。

SQL> CREATE OR REPLACE PROCEDURE P_AUTO_TRANS AS
  2 PRAGMA AUTONOMOUS_TRANSACTION;
  3 BEGIN
  4 INSERT INTO T_AUTO_TRANS VALUES (1, 'TEST');
  5 INSERT INTO T_AUTO_TRANS VALUES (2, 'TEST');
  6 FOR I IN (SELECT COUNT(*) CNT FROM T_AUTO_TRANS) LOOP
  7 DBMS_OUTPUT.PUT_LINE('P_AUTO_TRANS:' || I.CNT);
  8 END LOOP;
  9 P_TEST;
  10 P_TEST_AUTO;
  11 COMMIT;
  12 END;

   过程已创建。  

SQL> INSERT INTO T_AUTO_TRANS VALUES (1, 'TEST');

  已创建 1 行。

SQL> EXEC P_AUTO_TRANS
  P_AUTO_TRANS:2
  P_TEST:3
  P_TEST_AUTO:1
  PL/SQL 

     过程已成功完成。

  建立一个自治事务,分别调用一个普通过程和一个声明了自治事务的过程,结果可以看到,自治事务调用普通过程,可以看到自治事务所进行的修改,而对于自治事务调用的自治事务过程,是看不到自治事务所进行的修改的。

  从这一点看,自治事务更像是在单独的会话中执行,它的事务状态不会影响当前的事务,它也不会看到当前事务没有提交的修改。

 

 

总结:要想在SELECT语句中对表进行修改,可以使用自治事务(Autonomous TransactionsAT)。自治事务(Autonomous Transactions)是由另外一个事务调用的,这个叫事务做主事务(Main TransactionMT)。自治事务(Autonomous Transactions)的提交(commit)和回滚(rollback)并不影响主事务(MT)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值