본문 바로가기
Back-End/Database

Transaction

by 코젼 2024. 7. 23.
728x90
반응형

목차

    트랜잭션을 잘게 나누면 보정배치가 쉬워지고 트랜잭션이 왜 실패했는지 추적할 수 있다.
    충돌 횟수를 고려하여 락 종류를 선택한다.
    자기 자신만 접근하는 로직일 경우 충돌이 적을 확률이 높아진다.
    
    트랜잭션 작은 단위로 나눌 시, Manager (application 계층) 추가 
    또는 service 에서 필요한 repository 를 DI 받아서 하나의 메서드에서 처리한다.
    만약 연관 관계가 맺어져있다면?
    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' 카테고리의 다른 글

    재귀적 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
    MySQL - group by, having, join  (0) 2022.07.18

    댓글