2010-11-19 4 views
16

단일 WebLogic 클러스터에서 실행중인 J2EE 응용 프로그램의 인스턴스가 2 개 있습니다.오라클에서 MERGE를 수행 할 수 있습니까?

이러한 응용 프로그램은 어느 시점에서 백 엔드 Oracle 데이터베이스에 레코드를 삽입하거나 업데이트하기 위해 MERGE를 수행합니다. MERGE는 지정된 기본 키가있는 행이 있는지 여부를 확인합니다. 그것이 있으면 업데이트하십시오. 그렇지 않은 경우 삽입하십시오.

이제 두 개의 app 인스턴스가 기본 키가 100 인 행을 삽입하거나 업데이트하려고한다고 가정합니다. 행이 존재하지 않는다고 가정합니다. 병합의 "확인"단계에서 두 행은 병합되지 않았으므로 두 행 모두 삽입을 시도합니다. 그런 다음 고유 한 키 제약 조건 위반이 발생합니다.

내 질문은 : Oracle에 원자력이 있습니까? 내 응용 프로그램에서 SQL 만 실행할 수 있다는 점을 제외하면 PL/SQL의 INSERT ... FOR UPDATE과 비슷한 효과가있는 것을 찾고 있습니다.

편집 : 명확하지 않았습니다. 이 오류가 계속 발생하는 동안 MERGE 문을 사용하고 있습니다. 것은 "수정"부분 만이 전체 병합이 아니라 원자 (atomic)라는 것입니다.

+2

병합은 원자 적입니다. 완전한 작업 단위로 작동하거나 실패합니다. 오라클이 다중 버전 일관성을 구현 한 결과입니다. 여러 합병을 seralize 할 무언가를 찾고있는 것처럼 들리십니까? 당신은 오라클의 seralizable 트랜잭션을 사용해 볼 수도 있습니다.하지만 그것은 아마도 유일한 키 제약에서 트랜잭션 에러를 직렬화 할 수없는 에러로 바뀔 것입니다. –

+0

내 데이터베이스/멀티 스레드 vocab이 잘못되었을 수 있습니다. 나의 이해는 "작업의 전체 단위로서의 실패 또는 실패"를 트랜잭션이라고합니다. 원자 단위로, 다른 병합 처리 중에 병합이 발생할 수 없다는 것을 의미했습니다. 병합을 직렬화하는 것에 관해, 나는 그것을 읽어야 할 것이다. 감사. – Russell

+1

@Russell, 원 자성은 트랜잭션의 한 속성 일뿐입니다. 그리고 성공 또는 실패를 의미합니다. exapmle의 경우 http://en.wikipedia.org/wiki/ACID 및 http://download.oracle.com/docs/cd/E11882_01/server.112/e16508/transact.htm#sthref1298을 참조하십시오. –

답변

6

두 번째 세션의 MERGE 문은 해당 세션이 커밋 될 때까지 첫 번째 세션이 수행 한 삽입을 "볼"수 없습니다. 트랜잭션의 크기를 줄이면 트랜잭션이 발생할 확률이 줄어 듭니다.

또는 주어진 기본 키의 모든 레코드가 동일한 세션에 제공되도록 데이터를 정렬하거나 파티셔닝 할 수 있습니까? "기본 키 mod N"과 같은 간단한 함수는 N 개의 세션에 균등하게 분산되어야합니다.

btw 두 레코드가 동일한 기본 키를 갖고 있으면 두 번째 레코드가 첫 번째 레코드를 덮어 씁니다. 좀 이상하다.

+0

+1 응용 프로그램 수준 해결 방법. 감사. – Russell

+2

이 질문에 대답하지 않습니다. db를 공통 요소로 사용하는 두 개의 개별 응용 프로그램을 동기화하려는 경우 해결 방법이 작동하지 않습니다. – Dariusz

3

예, 그것이라고 .... MERGE

편집이 물 꽉을 얻을 수있는 유일한 방법은, 삽입 DUP_VAL_ON_INDEX 예외를 캐치 (적절하게 업데이트가 그것을 처리, 혹은 다른 레코드를 삽입하는 것입니다). 이것은 PL/SQL로 쉽게 수행 할 수 있지만 사용할 수는 없습니다.

해결 방법이 필요합니다. Java에서 dup_val_on_index를 catch하고 추가 UPDATE를 다시 발행 할 수 있습니까? 의사 코드에서

:

try { 
    // MERGE 
} 
catch (dup_val_on_index) { 
    // UPDATE 
} 
+0

하하하 감사합니다. 나는 명확한 질문을 편집했다. – Russell

+0

좋아, 나는 주말 후에 좀 더 살펴볼 것이다! –

+0

PL/SQL을 사용할 수 있습니까? 내가 발견 한 첫 번째 일은 예외 처리 (dup_val_on_index가 업데이트 될 때)가있는 삽입이이 수밀을 얻는 유일한 방법임을 제안합니다. –

2

내가 그 MERGE 당신이 설명하는 방식으로 작동 할 놀라지,하지만 나는 그것을해야하는지 여부를 말할 충분히 그것을 사용하지 않았습니다.

어떤 경우에도 병합을 실행하려는 트랜잭션의 격리 수준이 SERIALIZABLE로 설정되어있을 수 있습니다. 나는 그것이 당신의 문제를 해결할 것 같아요.

13

MERGE와 같이 문제가되지 않습니다. 오히려 문제는 응용 프로그램에 있습니다.

create or replace procedure upsert_t23 
    (p_id in t23.id%type 
     , p_name in t23.name%type) 
is 
    cursor c is 
     select null 
     from t23 
     where id = p_id; 
    dummy varchar2(1); 
begin 
    open c; 
    fetch c into dummy; 
    if c%notfound then 
     insert into t23 
      values (p_id, p_name); 
    else 
     update t23 
      set name = p_name 
      where id = p_id; 
    end if; 
end; 

따라서 T23의 MERGE와 동일한 PL/SQL입니다. 두 세션이 동시에 그것을 호출하면 어떻게됩니까?

SSN1> exec upsert_t23(100, 'FOX IN SOCKS') 

SSN2> exec upsert_t23(100, 'MR KNOX') 

SSN1이 먼저 도착하고 일치하는 레코드를 찾지 않고 레코드를 삽입합니다. SSN1은 커밋되지 않고 SSN1이 커밋되기 전에 레코드를 찾지 않고 레코드를 삽입하고을 정지시킵니다. SSN1이 100의 고유 인덱스 노드를 잠그기 때문에 SSN2가 DUP_VAL_ON_INDEX 위반을 던집니다.

MERGE 문은 완전히 똑같은 방식으로 작동합니다. 두 세션 모두 on (t23.id = 100)을 확인하고 찾지 않고 INSERT 분기로 이동합니다. 첫 번째 세션은 성공하고 두 번째 세션은 ORA-00001을 던집니다.

이 문제를 처리하는 한 가지 방법은 비관적 잠금을 도입하는 것입니다.UPSERT_T23 절차의 시작에서 우리는 테이블을 잠글 :

... 
lock table t23 in row shared mode nowait; 
open c; 
... 

이제 SSN1 도착, 잠금을 잡고 이전과 같이 진행된다. SSN2가 도착하면 잠금을 얻을 수 없으므로 즉시 실패합니다. 두 번째 사용자에게는 실망스러운 점이 있지만 최소한 매달려 있지는 않으며, 다른 사람이 동일한 기록을 작성하고 있음을 알 수 있습니다.

선택할 필요가 없으므로 SELECT ... FOR UPDATE와 동일한 INSERT 구문이 없습니다. 따라서 MERGE에 대한 구문도 없습니다. 당신이해야 할 일은 MERGE를 발행하는 프로그램 유닛에 LOCK TABLE 문을 포함시키는 것입니다. 이것이 가능한지 여부는 사용중인 프레임 워크에 따라 다릅니다.

+1

고마워, 내 질문에 내가 설명하려고했던 것을 완벽하게 표현했다. 어떻게 문제를 처리 할 것인가, 잠금 문제가 PL/SQL의 일부가 아닌가? 나는 해결 방법을 찾고/솔루션 내 애플 리케이션에서 호출 할 수있는 오라클의 SQL을 사용합니다. 나는 SELECT ... FOR UPDATE와 동일한 INSERT를 찾지 못했다. (내가 그런 식으로 생각하게 만들었지 만).MERGE 문 (따라서 질문의 제목)을 통해 병합되는 행을 잠글 수있는 방법이 있는지 찾았습니다. 모든 대답과 지식을 주셔서 감사합니다. – Russell

+1

행 공유 (행 공유가 아님) 테이블을 잠그면 거의 아무 것도 수행하지 않습니다. 다른 세션이 Exclusive 테이블 잠금을 얻는 것을 방지합니다. 다른 세션이 업데이트/삽입/삭제되는 것을 방지하지 않습니다. btw를 사용하면 "select .. for update"문을 실행하면 행 공유 잠금이 자동으로 획득됩니다. "공유 행 독점"모드는 다른 세션이 테이블을 변경하는 것을 방지하며 다른 세션에 커밋되지 않은 변경 사항이있는 경우이를 획득 할 수 없습니다. 이것은 거의 독점적 인 자물쇠처럼 복원력이 있습니다. 이를 사용하면 "단일 사용자"시스템과 같은 모든 동시 업데이트를 방지 할 수 있습니다. – redcayuga

관련 문제