2010-06-22 5 views
1

저장 프로 시저를 10 번 실행하는 PHP 코드가 있습니다. 하나의 스토어드 프로 시저 호출이 실패하면 계속 진행해야하고 마지막에는 트랜잭션을 커밋해야합니다.Oracle PL/SQL - OCI8을 실행하는 PHP에서 자동 롤백이 언제 실행됩니까?

그것은 기본적으로 다음과 같습니다 : 말, 제기 예외, 5 저장된 프로 시저 호출이있는 경우

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

내 질문은, 것이라고 롤 다시 모든 저장된 프로 시저는 그 시점까지 호출한다 ?

+0

좋은 질문입니다. 다섯 번째 저장된 proc 호출이 실패 할 때 어떤 행동을 보이고 있습니까? – FrustratedWithFormsDesigner

+0

아무 것도 굴러 가지 않습니다. 성공적인 실행은 모두 커밋됩니다. 그래서이 사이트의 1.10.4 (http://soft.buaa.edu.cn/oracle/bookshelf/Orilly/langpkt/ch01_10.htm)에서 처리되지 않은 예외가 롤백 될 것이므로 혼란 스럽습니다. 컨트롤이 호출 응용 프로그램으로 반환되었습니다. –

+0

이 페이지의 내용은 다르게되어 있습니다. http://www.stanford.edu/dept/itss/docs/oracle/10g/appdev.101/b10807/07_errs.htm#i3372 "처리되지 않은 예외 잡기"섹션에는 "처리되지 않은 예외 또한 서브 프로그램을 성공적으로 종료하면 PL/SQL은 OUT 매개 변수에 값을 할당하지만 처리되지 않은 예외로 종료하면 PL/SQL은 NOCOPY 매개 변수가 아닌 경우 OUT 매개 변수에 값을 할당하지 않습니다.또한 저장된 서브 프로그램이 처리되지 않은 예외로 실패하는 경우 PL/SQL은 서브 프로그램이 수행 한 데이터베이스 작업을 롤백하지 않습니다. " –

답변

1

각 프로 시저가 동일한 세션에서 실행되고 이들 중 누구도 커밋을 발행하지 않으면 변경 사항을 롤백 할 수 있습니다. 루프 외부에서 연결을 연 다음 그 안에서 모든 작업을 수행해야합니다. 이제부터는 루프를 통해 매번 연결되므로 비효율적이며 원하는 작업을 수행 할 수 없습니다. 루프 외부에서 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); 
+0

존재하지 않는 것에 대한 사과 더 명시 적으로 ... getConn() 함수는 싱글 톤 연결을 반환하므로 모두 동일한 연결입니다. 당신의 대답은 내가 기대하는 바이지만 어떤 이유로 든 성공적인 모든 실행은 커밋되고 있습니다. 10 개의 실행 중 5 번째가 처리되지 않은 예외로 인해 실패하고 있습니다. –

+0

동일한 최종 결과를 사용하여 코드를 약간 편집하여 더 명확하게했습니다. –

+0

5 일에 실패하면 트랜잭션을 롤백합니까? 원래 코드의 커밋은 루프 내부에 있으며 루프를 통과 할 때마다 변경 사항이 영구적으로 적용됩니다. 루프 밖에서 커밋을 넣고 예외가 발생하면 전혀 커밋하지 않아야합니다. – DCookie

1

는 내가 PHP 드라이버, 그리고 오라클은 여기에 커밋 제어 생각합니다. This은 PHP 5.3.2 (PECL OCI8 1.4)에서 OCIExecute (기본값)를 호출 할 때 저장 프로 시저의 내용과 관계없이 명령문을 커밋 함을 나타냅니다.

+0

커밋하지 않은 동등한 호출이 없으면 "기능"을 싫어할 것입니다. OP는 루프 처리를 수행하는 DB에서 다른 프로 시저를 만들어야 할 것입니다. – DCookie

+0

OCI_DEFAULT 옵션을 사용하여 자동 커밋을 방지합니다 (최신 버전의 PHP에서는 OCI_NO_AUTO_COMMIT라고 함). –

+0

@DCookie -Yup, 전통적인 사고 방식에 위배됩니다. 비슷한 일이 벌어지는 JDBC 코드의 문제를 해결할 때 먼저이 개념을 뛰어 넘었습니다. – dpbradley

1

최근에 일부 테스트를 수행해야했습니다. 처리되지 않은 예외가 발생하면 오라클은 최상위 부분 인 begin 블록 또는 동일한 세션에 대한 커밋까지 부분 롤백을 수행합니다 (항상 이전 커밋으로 되돌아 오는 것은 아닙니다).

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; 

다음이 실행 : INT ID와 VARCHAR2 발과 시저와 테이블을 감안할 때 다시하여 '초기화하기'에서 커밋에

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 모든 방법을 (ONE뿐만 아니라 롤백) .

대 (사이에서, 각각의 블록에 대해,/집으로 전부 용 F5) 또는 SQLPLUS를 F9를 자동 커밋 (어느 꺼부터) 위해 이러한 excecuting :

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; 

예외는 THREE 내에 ocurring 'ONE'직후로 롤백합니다. 그러나 'ONE'은 행 잠금 (TOAD의 세션 브라우저로 확인)을 보유하고 있기 때문에 롤백하거나 커밋해야합니다. 이것을 'init'호출 내에서 커밋으로 되돌아 가지 않고 행을 잠그지 않기 때문에 부분 롤백이라고 부릅니다. 나는이 사건이 PHP가하고있는 일이나 다른 커넥터들에 더 가깝다고 가정하고있다.

관련 문제