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 문을 포함시키는 것입니다. 이것이 가능한지 여부는 사용중인 프레임 워크에 따라 다릅니다.
출처
2010-11-20 08:54:31
APC
병합은 원자 적입니다. 완전한 작업 단위로 작동하거나 실패합니다. 오라클이 다중 버전 일관성을 구현 한 결과입니다. 여러 합병을 seralize 할 무언가를 찾고있는 것처럼 들리십니까? 당신은 오라클의 seralizable 트랜잭션을 사용해 볼 수도 있습니다.하지만 그것은 아마도 유일한 키 제약에서 트랜잭션 에러를 직렬화 할 수없는 에러로 바뀔 것입니다. –
내 데이터베이스/멀티 스레드 vocab이 잘못되었을 수 있습니다. 나의 이해는 "작업의 전체 단위로서의 실패 또는 실패"를 트랜잭션이라고합니다. 원자 단위로, 다른 병합 처리 중에 병합이 발생할 수 없다는 것을 의미했습니다. 병합을 직렬화하는 것에 관해, 나는 그것을 읽어야 할 것이다. 감사. – Russell
@Russell, 원 자성은 트랜잭션의 한 속성 일뿐입니다. 그리고 성공 또는 실패를 의미합니다. exapmle의 경우 http://en.wikipedia.org/wiki/ACID 및 http://download.oracle.com/docs/cd/E11882_01/server.112/e16508/transact.htm#sthref1298을 참조하십시오. –