프로그래밍백엔드 개발자

SQL에서 데이터에 대한 동시 액세스를 올바르게 제한하는 방법(잠금 메커니즘, 잠금 수준 및 관리 방법)은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사

다중 사용자 데이터베이스의 등장과 함께 동일한 데이터를 동시 수정하는 것을 제한하는 과제가 발생했습니다. 이는 병렬 변경을 방지하고 데이터의 무결성을 유지하는 다양한 잠금 메커니즘(잠금 관리)의 출현으로 이어졌습니다.

문제

액세스 제어가 없으면 동시 작업이 데이터 손상 또는 손실로 이어질 수 있습니다: 예를 들어, 두 개의 트랜잭션이 동시에 하나의 행을 업데이트하고, 한 트랜잭션의 변화가 손실될 수 있습니다. 충분히 엄격하지 않은 잠금은 경쟁 문제(경쟁 조건)를 초래하고, 과다한 잠금은 성능 저하(교착 상태, 경쟁)를 초래합니다.

해결책

현대의 DBMS에는 다양한 수준의 잠금(행 수준, 페이지 수준, 테이블 수준)과 다양한 모드(공유, 배타적, 업데이트)가 있습니다. 프로그래머는 트랜잭션 격리 설정 및 명시적 잠금 명령(예: SELECT ... FOR UPDATE)을 통해 이를 관리할 수 있습니다.

코드 예시:

-- 트랜잭션이 완료될 때까지 행을 잠금 BEGIN TRANSACTION; SELECT * FROM users WHERE id = 1 FOR UPDATE; UPDATE users SET name = 'New Name' WHERE id = 1; COMMIT;

주요 특징:

  • 잠금의 세분성(행, 페이지, 테이블)
  • 명시적 및 암시적 잠금(트랜잭션 및 특수 지시어를 통해)
  • 격리 수준이 잠금 스키마에 미치는 영향

트릭 질문.

읽기 잠금(공유 잠금)과 쓰기 잠금(배타적 잠금) 간의 차이는 무엇인가요?

공유 잠금은 여러 트랜잭션이 동시에 데이터를 읽을 수 있도록 허용하지만, 변경은 허용하지 않습니다. 배타적 잠금은 오직 하나의 트랜잭션만 데이터 변경을 허용하고, 나머지 모든 트랜잭션은 접근을 금지합니다.


SELECT 명령이 잠금을 유발할 수 있나요?

일반적으로 SELECT는 잠금을 유발하지 않지만, SELECT ... FOR UPDATE를 사용하거나 높은 격리 수준(예: SERIALIZABLE)일 경우, DBMS가 행을 잠글 수 있습니다.

코드 예시:

SELECT * FROM products WHERE id = 10 FOR UPDATE;

잠금이 항상 "잃어버린 업데이트"를 방지하나요?

아니요, 잠금 수준이나 격리가 잘못 선택된 경우, 한 트랜잭션의 변경이 다른 트랜잭션으로 인해 손실되는 "잃어버린 업데이트"가 발생할 수 있습니다. 동시성 관리 메커니즘을 신중하게 선택해야 합니다.

일반적인 실수 및 안티 패턴

  • 격리 수준의 부적절한 선택(너무 낮거나 너무 높음)
  • 중요한 쿼리에서의 충분하지 않은 명시적 잠금
  • 성능 저하를 초래하는 전역(테이블 수준) 잠금 남용
  • 완료되지 않은 트랜잭션으로 인해 잠금을 해제하지 않음

실제 사례

부정적인 케이스

분석 부서에서 두 프로그램이 동시에 주문 상태를 업데이트합니다. 빠른 처리를 위해 READ UNCOMMITTED 수준으로 설정하여 행을 잠그지 않았습니다. 이로 인해 충돌과 "잃어버린" 업데이트가 발생하여 일부 데이터가 손상되었습니다.

장점:

  • 초기 속도 좋음

단점:

  • 중요한 데이터 손실/손상
  • 복구의 어려움

긍정적인 케이스

판매 부서에서 중요한 부분은 TRANSACTION + SELECT ... FOR UPDATE로 감쌌습니다. 행 수준에서 읽기 및 업데이트 작업을 분리했습니다.

장점:

  • 데이터 무결성 보장
  • 손실 및 변경 중복 없음

단점:

  • 특정 경우 잠금으로 인해 업데이트가 약간 느림