728x90

먼저 알고 가면 좋은 것들

ACID

https://hanamon.kr/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98-acid-%EC%84%B1%EC%A7%88/

 

[데이터베이스] 트랜잭션의 ACID 성질 - 하나몬

트랜잭션이란 여러 개의 작업을 하나로 묶은 실행 유닛을 말한다. 데이터베이스 트랜잭션은 ACID라는 특성을 가지고 있다. ACID는 데이터베이스 내에서 일어나는 하나의 트랜잭션(transaction)의 안

hanamon.kr

 

Transaction 격리수준

https://zzang9ha.tistory.com/381#:~:text=%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98%20%EA%B2%A9%EB%A6%AC%20%EC%88%98%EC%A4%80(Isolation%20level)%EC%9D%B4%EB%9E%80%20%EB%8F%99%EC%8B%9C%EC%97%90%20%EC%97%AC%EB%9F%AC%20%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98,%EB%A5%BC%20%EA%B2%B0%EC%A0%95%ED%95%98%EB%8A%94%20%EA%B2%83%EC%9E%85%EB%8B%88%EB%8B%A4. 

 

[MySQL] - 트랜잭션의 격리 수준(Isolation level)

📎 글또 6기 포스팅 1. 미치도록 더웠던 7월의 회고 2. 사용자가 게시물을 작성할 때의 트랜잭션 처리 3. Spring AOP - (1) 프록시 패턴, 데코레이터 패턴 4. [MySQL] - 트랜잭션의 격리 수준(Isolati

zzang9ha.tistory.com

 

본론


JPA 는 기본적으로 데이터베이스 트랜잭션 격리 수준을 READ COMMITTED 정도로 가정한다.

만약 일부 로직에 더 높은 격리 수준이 필요하면 낙관적 락과 비관적 락 중에 하나를 사용하면 된다.

 

낙관적 LOCK

낙관적 lock 은 이름 그대로 트랜잭션 대부분은 충돌이 발생하지 않는다고 가정 하는 방법이다.

이것은 DB 에서 제공하는 LOCK 기능을 사용하는 것이 아니라 JPA 가 제공 하는 Version 관리 기능을 사용한다.

 

한마디로 DB 에서 LOCK 을 거는 것이 아닌 Application 단계에서 LOCK 을 거는 것이다.

 

비관적 LOCK

비관적 LOCK 은 트랜잭션의 충돌이 발생한다는 것을 가정하고 먼저 LOCK 을 거는 것이다.

대표적으로 select for update 가 있다.

 

JPA Version annotation 

낙관적 LOCK 과 비관적 LOCK 을 설명하기 전에 먼저 @Version 을 알아보자.

낙관적 LOCK 을 사용하려면 Version 어노테이션을 사용해서 버전 관리를 해야한다.

 

적용 가능한 타입은 다음과 같다.

  • Long
  • Integer
  • Short
  • Timestamp
@Version
private Integer money;

Version 어노테이션이 붙은 field 는 엔티티를 수정할 때마다 버전이 하나씩 자동으로 증가한다.

그리고 수정할대 조회 시점의 버전과 수정 시점이 다르면 예외가 발생한다.

 

주의할점

@Version 으로 추가한 버전 관리 Field 는 JPA 가 직접 관리하므로 임의로 수정해서는 안된다. (벌크 연산을 제외하고는)

만약 버전 값을 강제로 증가하려면 특별한 LOCK 옵션을 선택하면 된다.

 

JPA 에서 LOCK 사용

 

LOCK 을 적용 할수 있는 곳

  • EntityManger.lock()
  • EntityManger.find()
  • EntitiyManger.refresh()
  • Query.setLockMode()
  • @NamedQuery

 

JPA 낙관적 LOCK

OPTIMISTIC

@Version 만 적용했을 때는 엔티티를 수정해야 버전을 체크하지만 이 옵션을 추가하면 엔티티를 조회만 해도 버전을 체크한다.

한번 조회한 엔티티는 Transaction이 종료될때 까지는 다른 Transaction 에서 변경되지 않음을 보장한다.

 

사용 - 조회한 엔티티는 트랜잭션이 끝날 때 까지 다른 Transaction 에 의해 변경되지 않아야 한다.

조회 시점 부터 트랜잭션이 끝날 때 까지 조회한 엔티티가 변경되지않음을 보장

 

동작 - Transaction 을 커밋 할때 버전 정보를 조회해서 (Select query) 현재 엔티티 의 버전과 같은지 검증한다. 만약 같지 않으면 예외 발생

 

이점 - OPTIMISTIC 옵션은 DIRTY READ 와 NON-REPEATABLE READ 를 방지한다.

 

 

OPTIMISTIC_FORCE_INCREMENT

낙관적 LOCK 을 사용하면서  버전 정보를 강제로 증가한다.

 

사용 - 논리적인 단위의 엔티티 묶음을 관리할 수 있다. 예를 들어 게시물과 첨 부파일이 일대다, 다대일의 양방향 연관관계이고 

첨부파일이 연관관계의 주인이다. 게시물을 수정하는 데 단순히 첨부파일만 추가하면 게시물의 버전은 증가하지 않는다.

해당 게시물은 물리적으로는 변경되지 않았지만, 논리적으로는 변경되었다. 

이때 게시물의 버전도 강제로 증가하려면 OPTIMISTIC_FORCE_INCREMENT 를 사용하면 된다.

동작 - 엔티티를 수정하지 않아도 트랜잭션을 커밋할 때 UPDATE 쿼리를 사용해서 버전 정보를 강제로 증가시킨다.

이때 데이터베이스의 버전이 엔티티 의 버전과 다르면 예외가 발생한다. 

추가로 엔티티를 수정하면 수정 시 버전 UPDATE가 발생한다. 따라서 총 2번의 버전 증가가 나타날 수 있다.

이점 - 강제로 버전을 증가해서 논리적인 단위의 엔티티 묶음을 버전 관리할 수 있다.

 

 

JPA 비관적 락

JPA가 제공하는 비관적 락은 데이터베이스 트랜잭션 락 메커니즘에 의존하는 방법이다. 

주로 SQL 쿼리에 select for update 구문을 사용하면서 시작하고 버전 정보는 사용하지 않는다. 

비관적 락은 주로 PESSIMISTIC_WRITE 모드를 사용한다.
비관적 락은 다음과 같은 특징이 있다.

  • 엔티티가 아닌 스칼라 타입을 조회할 때도 사용할 수 있다.
  • 데이터를 수정하는 즉시 트랜잭션 충돌을 감지할 수 있다.


PESSIMISTIC_WRITE

비관적 락이라 하면 일반적으로 이 옵션을 뜻한다. 데이터베이스에 쓰기 락을 걸때 사용한다.


사용 -  데이터베이스에 쓰기 락을 건다.
동작 - 데이터베이스 select for update 를 사용해서 락을 건다.
이점 - NON-REPEATABLE READ를 방지한다. 락이 걸린 로우는 다른 트랜잭션이 수정할 수 없다.

 


PESSIMISTIC_READ


데이터를 반복 읽기만 하고 수정하지 않는 용도로 락을 걸 때 사용한다. 일반적 으로 잘 사용하지 않는다.

데이터베이스 대부분은 방언에 의해 PESSIMISTIC_WRITE로 동작한다.

 


PESSIMISTIC_FORCE_INCREMENT

 

비관적 락중 유일하게 버전 정보를 사용한다. 비관적 락이지만 버전 정보를 강제
로 증가시킨다. 하이버네이트는 nowait 를 지원하는 데이터베이스에 대해서 for update nowait 옵션을 적용한다.

728x90