락(Lock)

연어는결국강으로·2023년 12월 18일
0

DB 공부

목록 보기
4/5

1. Lock의 종류

1. 테이블 락(Table Lock)

  • 특정 작업이 전체 테이블을 락으로 잠그는 경우, 다른 쿼리가 그 테이블에 대해 실행되기까지 대기해야 할 수 있습니다. 테이블 락은 대량의 데이터 변경 작업이나 테이블 구조 변경 작업에서 자주 발생합니다.

2. 행 락(Row Lock)

  • 특정 행(들)에 대한 작업이 실행 중일 때, 해당 행들은 락으로 잠겨 다른 트랜잭션이 해당 행들을 사용할 수 없게 됩니다. 이러한 락은 데이터베이스가 데이터의 일관성을 유지하기 위해 사용합니다.

3. 데드락(Deadlock)

  • 두 개 이상의 트랜잭션이 서로 다른 자원에 대해 락을 요청하고, 서로가 락을 보유한 자원을 기다리는 상황이 발생할 수 있습니다. 이를 데드락이라 하며, 이 경우 데이터베이스 시스템은 일반적으로 하나 이상의 트랜잭션을 중단시켜 데드락을 해결합니다.

4. 락 문제 해결 방법

  1. 데이터베이스 모니터링: 데이터베이스 모니터링 도구를 사용하여 현재 실행 중인 쿼리와 락 상태를 확인합니다.
  2. 쿼리 및 트랜잭션 최적화: 락을 발생시키는 쿼리나 트랜잭션을 최적화합니다. 가능하다면 락의 범위를 줄이거나, 락이 필요한 시간을 단축합니다.
  3. 분산된 트랜잭션 피하기: 여러 테이블 또는 행에 걸쳐 있는 트랜잭션을 가능한 분산시켜 데드락의 위험을 줄입니다.
  4. 데이터베이스 설정 검토: 락 타임아웃 및 트랜잭션 격리 수준(isolation level)과 같은 데이터베이스 설정을 검토하고 필요에 따라 조정합니다.
  5. 인덱싱: 적절한 인덱싱은 특정 조건을 만족하는 행을 빠르게 찾는 데 도움을 줄 수 있으며, 이로 인해 락이 필요한 시간을 줄일 수 있습니다.

데이터베이스 락은 복잡한 문제일 수 있으므로, 문제를 해결하기 위해서는 근본적인 원인을 이해하고 적절한 접근 방법을 선택하는 것이 중요합니다.


2. Lock을 무시하고 데이터를 조회할 수 있는가?

대부분의 SQL 데이터베이스 시스템에서는 특정 쿼리를 수행할 때 락에 영향을 받지 않도록 하는 방법이 있습니다. 이러한 쿼리는 대개 "dirty read" 또는 "non-blocking read"라고 불리며, 일반적으로 트랜잭션의 격리 수준(Isolation Level)을 조정하여 구현할 수 있습니다.

1. SQL Server의 NOLOCK 힌트 사용

SQL Server에서는 NOLOCK 힌트를 사용하여 특정 쿼리에 대해 락을 무시하고 데이터를 읽을 수 있습니다. 이 방법은 데이터의 일관성을 보장할 수 없지만, 락으로 인한 블로킹 없이 데이터를 읽는 데 유용합니다.

SELECT * FROM 테이블명 WITH (NOLOCK)

2. MySQL의 Non-locking Read

MySQL에서는 격리 수준(Isolation Level)을 READ UNCOMMITTED로 설정하여 락 없이 데이터를 읽을 수 있습니다. 하지만 이는 트랜잭션의 안전성을 해칠 수 있으므로 주의해야 합니다.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM 테이블명;
COMMIT;

3. 주의사항

  • 데이터 일관성: 이러한 방법은 트랜잭션의 격리 수준을 낮추어 "dirty read"를 허용하는 것이므로, 아직 커밋되지 않은 변경 사항을 읽을 수 있습니다. 이는 데이터의 일관성 문제를 일으킬 수 있습니다.
  • 사용 시나리오: 일반적으로 이러한 방법은 실시간으로 변하는 데이터가 아니라, 대량의 데이터를 빠르게 읽어야 하는 분석 쿼리 등에서 사용하는 것이 좋습니다.
  • 데이터베이스 특성: 사용 중인 데이터베이스의 특성과 격리 수준에 대한 이해가 필요합니다. 각 데이터베이스 시스템마다 격리 수준을 설정하는 방법이 다를 수 있습니다.

이러한 방법을 사용할 때는 데이터의 일관성과 정확성이 필수적이지 않은 경우에 한하여 사용하는 것이 좋으며, 가능한 한 주의를 기울여야 합니다.


3. Spring에서는 어떻게 사용하지?

JPA(Java Persistence API)에서 트랜잭션의 격리 수준을 설정하여 READ UNCOMMITTED와 같은 비록킹(non-blocking) 읽기를 수행하는 것은 JPA 자체의 기능 범위를 넘어설 수 있습니다. 그러나 몇 가지 방법을 통해 이를 시도할 수 있습니다:

1. @Transactional 어노테이션 사용

스프링 프레임워크를 사용하는 경우 @Transactional 어노테이션을 통해 메서드 또는 클래스 수준에서 트랜잭션의 격리 수준을 설정할 수 있습니다. 하지만 READ UNCOMMITTED는 일반적으로 스프링에서 지원하는 기본 격리 수준 중 하나가 아니므로, 데이터베이스 특정 설정이 필요할 수 있습니다.

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Isolation;

@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void someMethod() {
    // ...
}

2. 네이티브 쿼리 사용

JPA에서 직접 트랜잭션 격리 수준을 설정하는 것은 일반적이지 않습니다. 대신, JPA의 EntityManager를 사용하여 네이티브 SQL 쿼리를 실행할 수 있습니다. 이 방법은 데이터베이스에 직접 SQL 명령을 보내므로, JPA의 추상화를 벗어나게 됩니다.

entityManager.createNativeQuery("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED").executeUpdate();
List<Object> results = entityManager.createNativeQuery("SELECT * FROM 테이블명").getResultList();

3. 데이터베이스 세션 설정

어플리케이션 또는 데이터베이스 연결 수준에서 트랜잭션 격리 수준을 설정할 수 있습니다. 이는 일반적으로 JPA 설정이나 데이터베이스 연결 설정에서 수행됩니다.

4. 주의사항

  • READ UNCOMMITTED 격리 수준은 "dirty read"를 허용합니다. 이는 아직 커밋되지 않은 변경 사항을 읽을 수 있으며, 데이터의 정확성과 일관성이 중요한 어플리케이션에서는 사용을 피해야 합니다.
  • 이러한 변경은 어플리케이션의 다른 부분에 영향을 줄 수 있으므로 주의가 필요합니다.

JPA는 데이터 접근에 대한 표준화된 접근 방식을 제공하지만, 특정 데이터베이스의 고급 기능을 활용하기 위해서는 JPA의 범위를 벗어나는 경우가 있습니다. 따라서 이러한 특정 사례에서는 JPA의 한계를 이해하고 적절한 방법을 선택하는 것이 중요합니다.

0개의 댓글