Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
何时在执行Oracle PL/SQL-OCI8的PHP中执行自动回滚?_Php_Oracle_Plsql_Transactions - Fatal编程技术网

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

何时在执行Oracle PL/SQL-OCI8的PHP中执行自动回滚?,php,oracle,plsql,transactions,Php,Oracle,Plsql,Transactions,我有PHP代码,可以执行存储过程10次。如果一个存储过程调用失败,它应该继续,并在最后提交事务 基本上是这样的: $connection = getConn(); foreach($row as $i=>$j) { $SQL = "BEGIN MYPROC.EXECUTE(:VAL1, :VAL2); END;"; $statement = OCIParse($connection, $SQL); oci_bind_by_name($statement, 'VAL1', $

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

基本上是这样的:

$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);

我的问题是,如果在第5次存储过程调用中出现异常,是否会回滚到该点的所有存储过程调用?

只要每个过程都在同一个会话中执行,并且没有一个过程发出提交,那么它们所做的更改就可以回滚。您应该在循环外部打开连接,然后在循环内部完成所有工作。现在,您每次都通过循环进行连接,这是低效的,并且不允许您执行您想要执行的操作。您还应该将commit语句置于循环之外

也许是这样的:

$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);

我认为PHP驱动程序,而不是Oracle,在这里控制提交。似乎表明,从PHP5.3.2(PECL OCI8 1.4)开始,每次调用OCIExecute(默认情况下)都会提交语句,而不管存储过程中有什么内容。

最近不得不对此进行一些测试。当发生未经处理的异常时,Oracle似乎会对同一会话执行部分回滚,直到包含begin块或commit的最顶端(并不总是返回到之前的commit)。给定一个具有int id、varchar2 val和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;
然后执行以下操作:

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;
在“init”中一直回滚到提交(也回滚了一个)

与按顺序执行这些命令相比(从Toad(自动提交关闭,每个块上F9,整个事件为f5)或介于/之间的Sqlplus):


三个以内出现的异常然后回滚到“一”之后。但是,“一”仍然需要回滚或提交,因为它持有行锁(使用TOAD中的会话浏览器进行验证)。将此调用为部分回滚,因为它不会一直返回到'init'调用中的提交,并将一行保持锁定。我假设这个例子更接近PHP和其他连接器的功能。

好问题。当第5次存储过程调用失败时,您现在有什么行为?它不会回滚任何内容。所有成功的处决都在进行中。这就是我感到困惑的原因,因为在这个站点()的1.10.4中,它表示当控件返回到调用的应用程序时,未处理的异常将回滚。这个页面的内容不同:在“捕获未处理的异常”部分,它声明,“未处理的异常也会影响子程序。如果成功退出子程序,PL/SQL会将值分配给OUT参数。但是,如果退出时出现未处理的异常,PL/SQL不会将值分配给OUT参数(除非它们是NOCOPY参数)。此外,如果存储的子程序因未处理的异常而失败,PL/SQL不会回滚子程序完成的数据库工作。“我不确定PHP和内联PLSQL是如何处理的,以及它们是否被视为上述注释中的“子程序”,或者它们是否被视为顶级程序,在这种情况下,我(假设)它会回滚吗?甲骨文不会为你回滚,是否存在未处理的异常。自己测试:对表执行更新。执行第二次更新,其中某个值=1/0,引发异常。现在从原始更新中重新选择行-它仍在更改。您有责任提交和回滚您的更改。抱歉没有更明确地说明。。。函数的作用是:返回一个单例连接,所以它是同一个连接。您的答案与我所期望的一样,但出于某种原因,所有成功的执行都被提交,尽管10次执行中的第5次执行失败,但出现了未处理的异常。为了更清楚,我稍微编辑了代码,最终结果相同。您是否在第5次执行失败时回滚事务?原始代码中的提交在循环中,这意味着每次通过循环,您的更改都是永久性的。您需要将commit放在循环之外,如果遇到异常,根本不需要这样做。此外,您也不需要每次通过循环都重新分析语句。只需重新绑定参数值就足够了。不过,您的示例不会在出现错误时中止处理。仅仅因为第5个过程生成了Oracle异常,并不意味着之前的所有更新都会回滚。如果您在异常发生后继续处理,并进行提交,则成功的更新仍然有效,并且您的提交会将其保存给后代。我讨厌这种“功能”,除非有相同的调用没有提交。我猜OP必须在DB中创建另一个执行循环处理的过程。我使用OCI_默认选项来防止自动提交(在较新版本的PHP中现在称为OCI_NO_auto_COMMIT)。@DCookie-Yup,它违背了传统的思维方式-在对JDBC代码进行故障排除时首次遇到了这个概念,当时发生了类似的事情。@Renderln-听起来您对驱动程序做了正确的操作以避免提交-我看到了您关于在应用程序代码中吞咽异常的另一条评论,并且只能猜测到这一点您的实际代码中存在逻辑问题。@dpbradley那么,我们是否都同意即使PHP应用程序代码出现SQL异常,Oracle也不会回滚事务?鉴于我已经关闭了自动提交功能,这种行为可以用上面DCookie的回答来解释。
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;