2011-10-21 3 views
4

을 방지하는 것은 나는 다음과 같은 경우라고 할 수 있습니다.이중 예약

이제 직원이 한 번에 하나의 작업 만 수행 할 수 있으므로 다음 PL/SQL 문을 사용하여 작업을 삽입합니다. 충돌하는 작업이 발견되는 경우, 작업은 (아마 여기에 오류를보고해야하지만,이 간단한 예를 들어 내가 그걸 무시하고있어) 추가되지 않습니다 :

create or replace procedure add_job 
(
    p_staff_id number, 
    p_job_name varchar2, 
    p_start_date date, 
    p_end_date date 
) 
as 
begin 
    insert into jobs 
    (
    select p_staff_id, p_job_name, p_start_date, p_end_date from dual 
    where not exists 
    (
     select 1 from jobs 
     where staff_id = p_staff_id 
     and (end_date > p_start_date) 
     and (start_date < p_end_date) 
    ) 
); 
end; 

문제는 그 나는 두 개의 서로 다른 일자리를 추가하는 경우 두 개의 서로 다른 세션을 한 다음 약속을 두 번 할 수 있습니다. 다음 즉 :

-- Session 1: 
add_job(1, 'Help Alice', to_date('2011/08/21 11:00:00', 'YYYY/MM/DD HH24/MI/SS'), to_date('2011/08/21 13:00:00', 'YYYY/MM/DD HH24/MI/SS')); 

-- Session 2: 
add_job(1, 'Help Bob', to_date('2011/08/21 12:00:00', 'YYYY/MM/DD HH24/MI/SS'), to_date('2011/08/21 14:00:00', 'YYYY/MM/DD HH24/MI/SS')); 

-- Session 1: 
commit; 

-- Session 2: 
commit; 

위, staff_id 일 12:00 13:00 사이에 예약 더블 될 것입니다. 즉 너무 광범위 잠금입니다 같은 느낌,

lock table jobs in exclusive mode; 

을 속임수를 썼는지 :

내 절차의 시작에 추가하는 것으로 보인다. 오라클을 조금 더 세밀하게 처리하도록 강요하는 방법이 있습니까? 가능한 경우 dbms_lock으로 주위를 돌보지 않을 것입니다. 이 page 힌트 select ... for update 트릭을 할 것이지만, 그것은 세부 사항을주지 않았다.

전체 테이블 잠금 또는 dbms_lock 잠금을 사용하지 않고 이중 예약을 중지 할 수있는 방법이 있습니까? (나는 Oracle 10g를 사용하고 있습니다.)

답변

-2

staff_id가 고유해야하는 경우 순서대로 생성해야합니다.

하고 삽입을 수행 할 때, 당신은 그냥이 방법을 수행

insert into jobs 
(
    select seq_staff_id.nextval, p_job_name, p_start_date, p_end_date from dual 
) 
+0

윌 우 : staff_id는 고유하지 않아야합니다. 한 명의 직원이 여러 작업을 완료 할 수 있습니다. 그것이 바로 요점이며, 직원들의 직업을 나열하고 그 직원에 대한 충돌을 방지합니다. – Clinton

+0

이 답변을 무시하십시오. 각 add_job에 대해 end_date를 지정하지 않아서 발생한 문제입니다. –

+0

당신은 작업 에서 1 선택할 경우 staff_id = p_staff_id 및 ( (종료일> p_start_date 및 시작일 p_end_date) 및 (START_DATE

0

당신은 직원이 작업의 특이점을 적용 할 데이터베이스 trigger를 사용할 수 있습니다.

개별 직원 구성원에 대한 중복 작업이있는 경우 삽입을 허용하지 않으므로 중복 작업을 얻을 수 없습니다.

질문이 지정된 경우 삽입을 검사하는 트리거로 인해 두 번째로 커밋 된 작업이 실패합니다.

현재 전체 테이블을 잠그는 것은 좋은 해결책이 아닙니다. 또한 SELECTFOR UPDATE을 사용하려고해도 두 개의 삽입을 방지 할 수 없습니다.

+0

트리거가 'ON COMMIT'인지 확인하십시오. –

2

이중 예약을 방지하려면 잠금 장치가 있어야합니다. 특정 직원을 잠글 필요가 있기 때문에, 내 조언은 당신이 삽입 문 앞에 직원의 행을 잠글 것입니다 :

select id from staff where id = p_staff_id for update; 

그 방법은 잠금이 하나의 직원 (당신이 행 레벨 잠금을 제공을)에 영향을 미친다.

+0

STAFF 테이블을 잠그면 항목이 JOBS 테이블에 삽입되는 것을 방지 할 수 있습니까? – Ollie

+1

두 번째 트랜잭션이 동일한 행을 잠그는 것을 방지하므로 모든 삽입이 동일한 프로 시저를 사용하거나 적어도 동일한 행을 잠급니다. –

+1

그래도 삽입 절차를 사용해야합니다. 다른 소스에서 JOBS 테이블에 삽입이 있으면 원래의 문제점이 여전히 발생할 수 있습니다. – Ollie

0

Onw 방식으로 점검 제약 조건과 함께 구체화 된보기를 사용할 수 있습니다. this old blog post of mine을 참조하십시오. 예를 들어 "1) 규칙 : 직원이 중복되는 프로젝트 배정을 가질 수 없음"이 매우 유사합니다.

주의 : 구체화 된 뷰를 유지 관리하는 것은 성능에 영향을 미치므로 적절한 성능 테스트없이 구현하지 마십시오.

0

작업은 시간의 둥근 상당히 큰 블록으로 할당되는 한 당신은 staff_id에 primay 키를 사용하여 새 테이블의 booked_time_slot을 만들 수 1 시간 삼십분 (1/60분의 24 * 30)

& 시간 (또는 날짜 & 슬롯 번호)

당신이 사용하는 각 시간 슬롯에 대한 행을 삽입하는 경우 : 합니다 (예를 들어 아래의 시작과 끝 시간과 상점 사이의 각 삼십분 슬롯을 얻는다 IT)

INSERT INTO booked_time_slot 
    SELECT p_staff_id,TO_DATE('2011/08/21 11:00:00', 'YYYY/MM/DD HH24/MI/SS') + 
     ((ROWNUM-1)*(1/24/60*30)) 
    FROM DUAL 
    CONNECT BY TO_DATE('2011/08/21 11:00:00', 'YYYY/MM/DD HH24/MI/SS') + 
     ((ROWNUM-1)*(1/24/60*30)) < 
      TO_DATE('2011/08/21 12:00:00', 'YYYY/MM/DD HH24/MI/SS') 

기본 키는 모든 중복을 중지합니다.