Oracle Lock Management Services (User Locks) 사용

Oracle Lock Management Services(사용자 잠금)란?

Oracle Lock Management Services(LMS), 흔히 사용자 잠금(User Locks)이라고 불리는 기능은 애플리케이션 레벨에서 데이터베이스 리소스에 대한 명시적인 잠금 메커니즘을 제공합니다. 이는 데이터베이스가 자동적으로 관리하는 암시적 잠금(Implicit Locking)과는 대조적입니다. 사용자 잠금은 데이터 무결성 및 동시성 제어를 위해 특정 상황에서 유용하게 활용될 수 있습니다.

사용자 잠금의 장점

  • 세밀한 제어: 데이터베이스 레벨의 잠금보다 더 세밀하게 잠금 동작을 정의하고 제어할 수 있습니다.
  • 애플리케이션 로직 통합: 잠금 메커니즘을 애플리케이션 로직에 직접 통합하여 복잡한 비즈니스 규칙을 반영할 수 있습니다.
  • 분산 환경 지원: 여러 데이터베이스 인스턴스에 걸쳐 있는 리소스에 대한 잠금을 관리할 수 있습니다.

사용 시나리오

사용자 잠금은 다음과 같은 상황에서 특히 유용합니다.

  • 병렬 처리 제어: 여러 프로세스가 동일한 데이터에 동시에 접근하는 것을 방지합니다.
  • 워크플로우 관리: 특정 단계를 완료하기 전에 리소스가 사용 가능한지 확인합니다.
  • 분산 트랜잭션 관리: 여러 데이터베이스에 걸쳐 있는 트랜잭션의 일관성을 유지합니다.

사용법: DBMS_LOCK 패키지

Oracle은 DBMS_LOCK 패키지를 통해 사용자 잠금 기능을 제공합니다. 이 패키지는 잠금 요청, 해제, 상태 확인 등 다양한 프로시저를 제공합니다.

주요 프로시저

  • ALLOCATE_UNIQUE: 고유한 잠금 식별자를 할당합니다.
  • REQUEST: 잠금을 요청합니다.
  • RELEASE: 잠금을 해제합니다.
  • CONVERT: 잠금 모드를 변경합니다.
  • SLEEP: 지정된 시간 동안 현재 세션을 일시 중단합니다.

예제: 사용자 잠금 요청 및 해제

다음은 DBMS_LOCK을 사용하여 사용자 잠금을 요청하고 해제하는 간단한 예제입니다.


DECLARE
  l_lockhandle VARCHAR2(100) := 'MY_APP_LOCK';
  l_return     NUMBER;
BEGIN
  -- 잠금 식별자 할당
  DBMS_LOCK.ALLOCATE_UNIQUE(lockname => l_lockhandle, lockhandle => l_lockhandle);

  -- 잠금 요청
  l_return := DBMS_LOCK.REQUEST(
      lockhandle        => l_lockhandle,
      lockmode          => DBMS_LOCK.X,
      timeout           => 10,
      release_on_commit => FALSE
  );

  IF l_return = 0 THEN
    DBMS_OUTPUT.PUT_LINE('잠금 획득 성공');
    -- 애플리케이션 로직 실행
    DBMS_OUTPUT.PUT_LINE('애플리케이션 로직 실행 중...');
    DBMS_LOCK.SLEEP(5); -- 5초 동안 대기

    -- 잠금 해제
    l_return := DBMS_LOCK.RELEASE(l_lockhandle);
    IF l_return = 0 THEN
      DBMS_OUTPUT.PUT_LINE('잠금 해제 성공');
    ELSE
      DBMS_OUTPUT.PUT_LINE('잠금 해제 실패: ' || l_return);
    END IF;
  ELSE
    DBMS_OUTPUT.PUT_LINE('잠금 획득 실패: ' || l_return);
  END IF;
END;
/

실행 결과


잠금 획득 성공
애플리케이션 로직 실행 중...
잠금 해제 성공

예제: 사용자 잠금과 트랜잭션

다음은 트랜잭션 내에서 사용자 잠금을 사용하여 데이터 일관성을 유지하는 예제입니다.


DECLARE
  l_lockhandle VARCHAR2(100) := 'MY_TX_LOCK';
  l_return     NUMBER;
BEGIN
  DBMS_LOCK.ALLOCATE_UNIQUE(lockname => l_lockhandle, lockhandle => l_lockhandle);
  l_return := DBMS_LOCK.REQUEST(
      lockhandle        => l_lockhandle,
      lockmode          => DBMS_LOCK.X,
      timeout           => 10,
      release_on_commit => FALSE
  );

  IF l_return = 0 THEN
    DBMS_OUTPUT.PUT_LINE('잠금 획득 성공');

    BEGIN
      -- 트랜잭션 시작
      DBMS_OUTPUT.PUT_LINE('트랜잭션 시작');
      -- 데이터 업데이트
      UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
      UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
      DBMS_OUTPUT.PUT_LINE('데이터 업데이트 완료');

      -- 커밋
      COMMIT;
      DBMS_OUTPUT.PUT_LINE('트랜잭션 커밋 완료');

      -- 잠금 해제
      l_return := DBMS_LOCK.RELEASE(l_lockhandle);
      IF l_return = 0 THEN
        DBMS_OUTPUT.PUT_LINE('잠금 해제 성공');
      ELSE
        DBMS_OUTPUT.PUT_LINE('잠금 해제 실패: ' || l_return);
      END IF;
    EXCEPTION
      WHEN OTHERS THEN
        -- 롤백
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('트랜잭션 롤백');
        l_return := DBMS_LOCK.RELEASE(l_lockhandle);
        IF l_return = 0 THEN
          DBMS_OUTPUT.PUT_LINE('잠금 해제 성공');
        ELSE
          DBMS_OUTPUT.PUT_LINE('잠금 해제 실패: ' || l_return);
        END IF;
        RAISE;
    END;
  ELSE
    DBMS_OUTPUT.PUT_LINE('잠금 획득 실패: ' || l_return);
  END IF;
END;
/

사전 준비


CREATE TABLE accounts (
    account_id NUMBER PRIMARY KEY,
    balance NUMBER
);

INSERT INTO accounts (account_id, balance) VALUES (1, 500);
INSERT INTO accounts (account_id, balance) VALUES (2, 500);
COMMIT;

정상 실행 결과


잠금 획득 성공
트랜잭션 시작
데이터 업데이트 완료
트랜잭션 커밋 완료
잠금 해제 성공

고려 사항

  • Deadlock: 사용자 잠금을 사용할 때 데드락이 발생하지 않도록 주의해야 합니다. 잠금 요청 순서를 일관되게 유지하거나, 타임아웃을 적절히 설정하여 데드락을 방지할 수 있습니다.
  • 성능: 사용자 잠금은 성능에 영향을 미칠 수 있습니다. 필요한 경우에만 사용하고, 잠금 획득 및 해제 시간을 최소화하는 것이 좋습니다.
  • 오류 처리: 잠금 획득 실패 시 적절한 오류 처리 로직을 구현해야 합니다.

결론

Oracle Lock Management Services는 애플리케이션 레벨에서 데이터베이스 리소스에 대한 명시적인 잠금 메커니즘을 제공하여 데이터 무결성 및 동시성 제어를 강화할 수 있습니다. DBMS_LOCK 패키지의 기능을 이해하고 적절히 활용함으로써, 개발자는 복잡한 비즈니스 요구 사항을 충족하는 안정적인 애플리케이션을 구축할 수 있습니다.

위로 스크롤