본문 바로가기
Back-End/Database

Transaction

by 코젼 2024. 7. 23.
728x90
반응형
트랜잭션을 잘게 나누면 보정배치가 쉬워지고 트랜잭션이 왜 실패했는지 추적할 수 있다.
충돌 횟수를 고려하여 락 종류를 선택한다.
자기 자신만 접근하는 로직일 경우 충돌이 적을 확률이 높아진다.

트랜잭션 작은 단위로 나눌 시, Manager (application 계층) 추가 
또는 service 에서 필요한 repositoryDI 받아서 하나의 메서드에서 처리한다.
만약 연관 관계가 맺어져있다면?
reservation.getUser().usePoint(amount)
exception 이후에 코드가 실행되지 않는지 체크하고 테스트 할 필요성이 있다.

트랜잭션 사용 논리적 흐름

구분해서 고려할 필요가 있다.

  • 실제 비즈니스 기반의 로직
  • 시스템 입장에서의 로직

동시성 제어

트랜잭션

공유락, 배타락 = 트랜잭션 동시성 제어 개념

순서대로 원자대로 시작되기 때문에 먼저 공유락을 걸고 배타락을 걸면
공유락을 사용하는 것들이 조회를 끝낼 때까지 수정 모두 불가
  • 공유락(읽기): 여러 트랜잭션이 하나의 데이터를 동시에 읽을 수 있는가?
    • @Lock(LockModeType.PESSIMISTIC_READ); // 나 쓰는 동안 읽기는 허용 가능
  • 배타락(쓰기): 여러 트랜잭션이 하나의 데이터를 동시에 접근하면 안된다.
    • @Lock(LockModeType.PESSIMISTIC_READ); //누구도 나 쓰는 동안 오지마.DB낙관락, 비관락 = DB 에서 동시성 제어
  • 낙관적 락: 실패 시 트랜잭션 자체가 실패한다.
  • 비관적 락: 성공 시 락을 점유하고 있기 때문에 다른 예약을 조회하거나 변경하려면 기다려야 한다.
  • 분산락

DB

낙관적 락

  • 자기 컬럼 두고 누가 그 사이에 값을 안 바꿨는지만 본다.
  • 낙관적 락은 실제로 락을 거는 것이 아니기 때문에 범위가 커져도 영향을 끼치지 않는다.
  • 낙관적 락은 업데이트 할 때 충돌(성공 유무)을 알 수 있다.

재시도

  • jpa update 쿼리 나가는 시점은 트랜잭션 종료 시점 이다. - lazy loading
  • 비즈니스 로직(횟수) 같은 경우 -> 서비스 / 알아서 성공해 -> 인프라 에 둔다.
  • retry 로직이 비즈니스 로직에서 관심사로 두어야 하는지 고민할 필요가 있다.
  • retry try-catch 사용 or @Retryable https://effortguy.tistory.com/487
  • 1차 캐싱 초기화 할 필요 없고 transaction 을 한 번 더 넣으면 된다. (낙관적락 조회, update)

비관적 락

  • 주로 배타 락과 연관이 있다. (write, read 불가)
  • 트랜잭션이 거대한 경우에 비관적 락이 걸려있는 경우 DB 커넥션이 한정적이기 때문에 DB 커넥션을 계속 붙잡고 기다리고 있어서 문제가 된다.
  • DB 커넥션을 가지고 있는 모든 로직에 영향을 끼친다.
  • 분산 락을 적용하면 해소 가능

분산락

  • 특정 id 에 대해서 분산 락을 획득하고 시작한다.
  • 버퍼 못 쓰기 때문에 분산 락 걸면 로딩 가능
  • 또는 연산이 자주 일어나는 것인데 예민한 것들에 자주 사용된다. (ex. 선착순 쿠폰)

Redis

캐싱의 목적으로 사용된다.

  • 라이브러리 사용 가능
    • 계속 구현하는 거 - Lettuce
    • pub/sub 으로 받는 거 - Redisson
  • ) kafka: 비동기, 메시지 큐 처리

동시성 제어 방식 도입

  1. lock 을 걸어야 하는 로직 선정
  2. 낙관 / 비관 중 어떤 것을 선정하는 것이 유의미할까?
  3. 트랜잭션의 범위는 어느 정도로 축소/확장해야 적용할 수 있을까?
  4. DB Lock 으로 충분히 제어하지 못하는 로직이 있는가? (트래픽이 쏟아졌을 때 못 버티는 이유는?)
    직접 적용해보고, 실제 문제점을 파악하는 것
  5. 분산 Lock 을 적용했을 때 해소 가능한가?

Log

Thread.currentThread().getName() //현재 스레드의 이름을 가져올 수 있다.
비즈니스 로직에 lock 의 영향 범위를 가시적으로 볼 수 있도록 log 를 넣는다.

 

낙관적 락을 사용할 때 @Transactional 을 사용할 필요가 없을까요?

낙관적 락 version 업데이트 해야하는데 @Transactional 이 없으면 read only 에러 표시

  • Transaction: 데이터의 원자성 보장 및 예외 시 롤백 처리
  • Lock: 데이터의 일관성 유지
  • 트랜잭션의 단위를 업무 단위로 적용: 하나의 Flow 에서 하나의 작은 단위의 작업이 실패했을 때(낙관적 락 실패) 롤백할 것인지 선택 or 보상 트랜잭션 처리하는 영역
  • 트랜잭션이 필요하지 않은 경우? 낙관적 락이 실패하든 말든 상관 없는 경우
728x90
반응형

'Back-End > Database' 카테고리의 다른 글

데이터베이스 인덱스  (0) 2025.03.10
재귀적 CTE(Common Table Expression)  (0) 2024.08.01
MySQL root 계정 비밀번호 재설정  (0) 2024.07.09
MySQL - Workbench, DB 종류  (0) 2022.07.19
MySQL - 실습문제  (0) 2022.07.18

댓글