何时在PHP执行Oracle PL / SQL-OCI8时会执行自动回滚?

我有PHP代码执行存储过程10次。 如果一个存储过程调用失败,它应该继续,并在最后提交事务。</ p>

它基本上如下所示:</ p>

  $ connection = getConn(); 

foreach($ row as $ i =&gt; $ j){
$ SQL =“BEGIN MYPROC.EXECUTE(:VAL1,:VAL2); END;”;
$ statement = OCIParse($ connection,$ SQL);

oci_bind_by_name($ statement,'VAL1',$ row [i] ['FIRSTVAL']);
oci_bind_by_name($ statement,'VAL2',$ row [ i] ['SECONDVAL']);

$ success = @OCIExecute($ statement,OCI_DEFAULT);
if(!$ success){
print'存储过程调用中的异常';
}
否{
打印'成功';
}

}
noci_commit($ connection);
</ code> </ pre>

我的问题是,如果有例外 例如,在第5个存储的proc调用中,是否会将所有存储的proc调用回滚到该点?</ p>
</ div>

展开原文

原文

I have PHP code that execute a stored procedure 10 times. If one stored procedure call fails, it should continue on, and at the end commit the transaction.

It basically looks like this:

$connection = getConn();

foreach($row as $i=>$j) {
  $SQL = "BEGIN MYPROC.EXECUTE(:VAL1, :VAL2); END;";
  $statement = OCIParse($connection, $SQL);

  oci_bind_by_name($statement, 'VAL1', $row[i]['FIRSTVAL']);
  oci_bind_by_name($statement, 'VAL2', $row[i]['SECONDVAL']);

  $success = @OCIExecute($statement, OCI_DEFAULT);
  if(!$success) {
    print 'Exception in stored proc call';
  }
  else {
    print 'Success';
  }

}
oci_commit($connection);

My question is, if there is an exception raised in, say, the 5th stored proc call, will that roll back all the stored proc calls up to that point?

drpzr64329
drpzr64329 Oracle为您“回滚”,未处理的未处理异常。自己测试:在表上执行更新。执行第二次更新,其中某些值=1/0,抛出异常。现在重新选择原始更新中的行-它仍然会更改。您负责提交和回滚您的更改。
10 年多之前 回复
donglan6777
donglan6777 我不确定如何处理PHP和内联PLSQL,如果它们被认为是上述评论中性质的“子程序”,或者它们被视为顶级程序,在这种情况下我(假设)它会回滚?
10 年多之前 回复
dqrq93879
dqrq93879 toolong
10 年多之前 回复
duanjiao5261
duanjiao5261 它没有回滚任何东西。成功的执行都是承诺。这就是为什么我感到困惑,因为在这个网站的1.10.4(soft.buaa.edu.cn/oracle/bookshelf/Oreilly/langpkt/ch01_10.htm)中,它表示当控制权返回到该网站时,未处理的异常将被回滚。调用应用程序
10 年多之前 回复
douxihui8270
douxihui8270 好问题。当第5个存储过程调用失败时,您现在会得到什么行为?
10 年多之前 回复

3个回答



只要每个过程在同一个会话中执行,并且它们都没有发出提交,那么它们所做的更改就可以滚动 背部。 您应该在循环外打开连接,然后在其中完成所有工作。 就像现在一样,你每次都要通过循环进行连接,效率低下,不允许你想做什么。 你还应该在循环外部使用commit语句。</ p>

这样的东西,可能是:</ p>

  $ SQL =“BEGIN MYPROC.EXECUTE  (:VAL1,:VAL2); END;“; 
$ connection = getConn();
$ statement = OCIParse($ connection,$ SQL);

foreach($ row as $ i =&gt; $ j ){

oci_bind_by_name($ statement,'VAL1',$ row [i] ['FIRSTVAL']);
oci_bind_by_name($ statement,'VAL2',$ row [i] ['SECONDVAL']);

$ success = @OCIExecute($ statement,OCI_DEFAULT);
if(!$ success){
print'存储过程调用中的异常';
oci_rollback($ connection);
此处退出处理。 ..
}
其他{
打印'成功';
}
}
oci_commit($ connection);
</ code> </ pre>
</ div>

展开原文

原文

As long as each procedure is executed in the same session, and none of them issue a commit, then the changes they make can be rolled back. You should open the connection outside the loop, then do all your work within that. As it stands now, you're connecting each time through the loop, which is inefficient and won't allow what you want to do. You should also take the commit statement outside the loop.

Something like this, perhaps:

$SQL = "BEGIN MYPROC.EXECUTE(:VAL1, :VAL2); END;";
$connection = getConn();
$statement = OCIParse($connection, $SQL);

foreach($row as $i=>$j) {

  oci_bind_by_name($statement, 'VAL1', $row[i]['FIRSTVAL']);
  oci_bind_by_name($statement, 'VAL2', $row[i]['SECONDVAL']);

  $success = @OCIExecute($statement, OCI_DEFAULT);
  if(!$success) {
    print 'Exception in stored proc call';
    oci_rollback($connection);
    exit processing here... 
  }
  else {
    print 'Success';
  }
}
oci_commit($connection);

dongxie2756
dongxie2756 too long
10 年多之前 回复
douzong2206
douzong2206 too long
10 年多之前 回复
dsjmrpym220113739
dsjmrpym220113739 但是,在出现错误的情况下,您的示例不会中止处理。 仅仅因为第5个过程生成Oracle异常并不意味着所有先前的更新都被回滚。 如果您在异常后继续处理并执行提交,则成功更新仍然有效,您的提交会将其保存为后代。
10 年多之前 回复
douchi0471
douchi0471 此外,您不需要每次循环重新分析语句。 只需重新绑定参数值就足够了。
10 年多之前 回复
douxishai8552
douxishai8552 你是在第五次失败时回滚你的交易吗? 您在原始代码中的提交是在您的循环中,这意味着每次循环时您的更改都是永久性的。 您需要将提交放在循环之外,如果遇到异常,则根本不执行此操作。
10 年多之前 回复
duanji2002
duanji2002 我稍微编辑了代码,结果相同,更清楚。
10 年多之前 回复
duandu2980
duandu2980 抱歉没有更明确...... getConn()函数返回一个单例连接,所以它是相同的连接。 你的回答是我的期望,但由于某种原因所有成功的执行都被提交,即使10次执行中的第5次因未处理的异常而失败。
10 年多之前 回复



最近必须对此进行一些测试。 当发生未处理的异常时,似乎Oracle会进行部分回滚,直到最顶层包含开始块或提交同一会话(并不总是一直回到先前的提交)。 给定一个带有int id和varchar2 val的表和proc:</ p>

  CREATE OR REPLACE PROCEDURE PROC_AUTO_COMMIT_TEST(
p_id int,p_val varchar2,p_cmd varchar2
)IS
BEGIN
if(p_cmd ='init')然后
从TEMP_AUTOCOMMIT_TEST中删除;
插入TEMP_AUTOCOMMIT_TEST值(1,'one');
插入TEMP_AUTOCOMMIT_TEST值(2,'two');
插入TEMP_AUTOCOMMIT_TEST值( 3,'三');
提交;

否则
更新TEMP_AUTOCOMMIT_TEST
设置val = p_val
其中id = p_id;

if if(p_cmd ='throw')然后
插入TEMP_AUTOCOMMIT_TEST值(3,'THREE'); - 抛出
结束if;
end if;

END PROC_AUTO_COMMIT_TEST;
</ code> </ pre>

然后执行:</ p>

  begin 
PROC_AUTO_COMMIT_TEST(0,null,'init “);

开始
PROC_AUTO_COMMIT_TEST(1,'ONE',null);
end;
begin
PROC_AUTO_COMMIT_TEST(2,'TWO',null);
PROC_AUTO_COMMIT_TEST(3,'THREE','throw') ;
end;
end;
</ code> </ pre>

一直回滚到'init'中的提交(也回滚过一次)。</ p>

按顺序排除这些(从Toad(自动提交关闭,每个块上的F9,整个事件的f5)或Sqlplus之间的/中间):</ p>

  begin 
PROC_AUTO_COMMIT_TEST(0,null,'init');

end;

begin
PROC_AUTO_COMMIT_TEST(1,'ONE',null);
end;

begin

PROC_AUTO_COMMIT_TEST(2,'TWO',null);
PROC_AUTO_COMMIT_TEST(3,'THREE', 'throw');
end;
</ code> </ pre>

在THREE中出现的异常然后回滚到'ONE'之后。 然而,'ONE'仍然需要回滚或提交,因为它持有行锁(在TOAD中使用会话浏览器验证)。 将此调用为部分回滚,因为它不会一直返回到'init'调用中的提交并使行保持锁定状态。 我假设这种情况更接近PHP可能正在做的事情和其他连接器。</ p>
</ div>

展开原文

原文

Had to do some testing on this recently. When an unhandled exception occurs it seems Oracle does a partial rollback up to the point of the topmost containing begin block or commit for the same session (not always all the way back to the prior commit). Given a table with int id and varchar2 val and proc:

CREATE OR REPLACE PROCEDURE PROC_AUTO_COMMIT_TEST( 
   p_id int, p_val varchar2, p_cmd varchar2
) IS
BEGIN
   if (p_cmd = 'init') then
        delete from TEMP_AUTOCOMMIT_TEST;
        insert into TEMP_AUTOCOMMIT_TEST values(1,'one');
        insert into TEMP_AUTOCOMMIT_TEST values(2,'two');
        insert into TEMP_AUTOCOMMIT_TEST values(3,'three');
        commit;  
   else   
        update TEMP_AUTOCOMMIT_TEST 
           set val = p_val
         where id = p_id;

         if (p_cmd = 'throw') then
            insert into TEMP_AUTOCOMMIT_TEST values(3,'THREE');  -- throws
         end if;
   end if;     
END PROC_AUTO_COMMIT_TEST;

Then executing this:

begin
    PROC_AUTO_COMMIT_TEST(0, null, 'init');   
    begin
        PROC_AUTO_COMMIT_TEST(1, 'ONE', null);
    end;
    begin
        PROC_AUTO_COMMIT_TEST(2, 'TWO', null);
        PROC_AUTO_COMMIT_TEST(3, 'THREE', 'throw');
    end;
end;

rollsback all the way back to the commit within the 'init' (ONE rolled back as well).

Versus excecuting these in order (from either Toad (autocommit off, F9 on each block, f5 for whole thing) or Sqlplus with /'s in between):

begin
    PROC_AUTO_COMMIT_TEST(0, null, 'init');   
end;

begin
    PROC_AUTO_COMMIT_TEST(1, 'ONE', null);
end;

begin
    PROC_AUTO_COMMIT_TEST(2, 'TWO', null);
    PROC_AUTO_COMMIT_TEST(3, 'THREE', 'throw');
end;

The exception ocurring within THREE then rolls back to just after the 'ONE'. However the 'ONE' still needs to either be rolled back or committed since it is holding a row lock (verified with Session Browser in TOAD). Calling this a partial rollback because it doesn't go all the way back to the commit within the 'init' call and leaves a row locked. I am assuming this case is closer to what PHP might be doing and other connectors.

I think the PHP driver, and not Oracle, is controlling the commit here. This seems to indicate that as of PHP 5.3.2 (PECL OCI8 1.4), each invocation of the OCIExecute (by default) will commit the statement, regardless of what is in the stored procedure.

doujiang1001
doujiang1001 -yes,我认为DCookie的答案解释了它 - 循环的后续迭代正在进行提交。
10 年多之前 回复
douxiajia6309
douxiajia6309 所以我们都同意即使SQL异常冒泡到PHP应用程序代码,Oracle也不会回滚事务吗? 鉴于我已经自动提交,这种行为将由DCookie的上述答案解释。
10 年多之前 回复
duanma8207
duanma8207 - 听起来你正在使用驱动程序做正确的事情以避免提交 - 我看到你关于吞下应用程序代码中的异常的其他一条评论,并且只能猜测你的实际代码中存在逻辑问题。
10 年多之前 回复
duanhuan1147
duanhuan1147 too long
10 年多之前 回复
dos3018
dos3018 我使用OCI_DEFAULT选项来阻止自动提交(现在在较新版本的PHP中称为OCI_NO_AUTO_COMMIT)。
10 年多之前 回复
dongluo3962
dongluo3962 too long
10 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐