DB-트랜잭션/락

Shaun·2022년 8월 28일
1

DB

목록 보기
3/5
post-thumbnail

트랜잭션

  • 간단히 말해 데이터베이스에서 하나의 거래를 안전하게 처리하도록 보장해주는 것을 뜻한다

  • 확실히 저장하던가 아니면 중간에 문제가 생겼다하면 아예 다 취소를 해버려 원상태로 만들어버린다.(원자성)

  • 데이터베이스에 정상 반영하는것을 '커밋' 이라하고 원상태로 돌리는것은 '롤백'이라 한다.

트랜잭션 ACID

  • 트랜잭션은 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 보장해야 한다.

원자성: 트랜잭션 내에서 실행한 작업들은 마치 하나의 작업인 것처럼 모두 성공 하거나 모두 실패해야 한다.

일관성: 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다. 예를 들어 데이터베이스에서 정한 무결성 제약 조건을 항상 만족해야 한다.

격리성: 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다. 예를 들어 동시에 같은 데이터를 수정하지 못하도록 해야 한다. 격리성은 동시성과 관련된 성능 이슈로 인해 트랜잭션 격리 수준 (Isolation level)을 선택할 수 있다.

지속성: 트랜잭션을 성공적으로 끝내면 그 결과가 항상 기록되어야 한다. 중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용해서 성공한 트랜잭션 내용을 복구해야 한다.

  • 격리성을 완벽히 보장하면( 하나씩 실행) 당연히 처리 속도가 현저히 느려진다. 이를 해결하기 위해 ANSI 표준은 트랜잭션의 격리 수준을 4단계로 나누어 정의했다.

트랜잭션 격리수준

READ UNCOMMITED(커밋되지 않은 읽기)
READ COMMITTED(커밋된 읽기)
REPEATABLE READ(반복 가능한 읽기)
SERIALIZABLE(직렬화 가능)

트랜잭션 사용법

  • 변경 쿼리를 날리고 그결과를 데이터 베이스에 반영하고 싶으면 'commit' 명령어를 날리면 됀다. / 반영하고 싶지 않으면 'rollback'

  • 커밋을 호출하기 전까지 임시로 저장한다고 보면 됀다. (마치 JPA 의 영속성 컨텍스트와 같다)

  • 자동커밋(set autocommit ture;)(디폴트)
  • 수동커밋 (set autocommit false;)
  • 커밋을 하기 전까지는 다른세션(사용자) 에게 변경값이 보이지 않으며 다른세션(사용자) 는 현재 DB데이터만 보이게 된다. 세션(변경 하려는자) 가 'commit' 명령어를 날리면 그때 DB에 반영되며 다른세션(사용자)도 데이터를 볼수 있다.
  • 예를들어 돈 입금,출금 같이 중요한 경우에 꼭 수동 커밋 모드를 사용해서 수동으로 커밋, 롤백 할 수 있도록 해야 한다. 보통 이렇게 자동 커밋 모드에서 수동 커밋 모드로 전환 하는 것을 트랜잭션을 시작한다고 표현한다.

DB-락

변경-락

  • 세션이 트랜잭션을 시작하고 데이터를 수정하는 동안에는 커밋이나 롤백 전까지 다른 세션에서 해당 데이터를 수정할 수 없게 막는 기능, 락을 건사람이 락을 반납해야 다른 사람이 사용가능

  • 수동커밋(트랜잭션시작)->데이터변경-> commit 명령어 -> lock 반납

  • 만약 락 타임아웃 시간이 지나면 락 타임아웃 예외가 발생한다.

조회-락

  • 일반적으로 조회는 락을 획득 하지 않는다.

  • 하지만 꼭필요한 경우에는 쿼리문 마지막에 select for update 라는 명령어를 사용

  • 트랜잭션 종료 시점까지 해당 데이터를 다른 곳에서 변경하지 못하도록 강제로 막아야 할 때 사용한다.

  • 똑같이 commit 명령어를 사용하면 락을 반납한다.

  • 만약 락 타임아웃 시간이 지나면 락 타임아웃 예외가 발생한다.

트랜잭션 활용

  • 당연히 트랜잭션을 사용하려면 '커넥션' 이 필요하다. 그래서 서비스단에서 커넥션,트랜잭션 처리, 커넥션 종료 까지 다 작성해야 한다.

  • 또한 트랜잭션을 사용하는 동안 같은 커넥션을 유지 해야한다. 그래야 같은 DB 세션 사용

  • 이번 실습에서는 같은 커넥션을 유지하기위해 Connection 을 파라미터로 넘겨서 만들어보자

  • 저번에 만들었던 코드들을 이용해 간단힌 계좌이체 로직을 만들었다. 예외인 경우도 포함했다. (트랜잭션 확인을 위한)
  • 기본적으로 트랜잭션은 비즈니스로직이 있는 서비스단에서 시작해야한다. 그래야 비즈니스 로직이 잘못되면 그 부분을 롤백할 수 있기때문이다.

  • 같은 커넥션을 넘겨주면서 같은 세션을 유지하도록 해주자 (자세한 코드는 생략)

  • 주의해야할점은 커넥션을 닫으면 안됀다는 점이다. 그래야 커넥션 유지가능 (서비스 단에서 닫아야함)

  • setAutoCommit 으로 수동커밋으로 전환해 트랜잭션 시작을 알린다. 그뒤로 비즈니니스 로직 -> 커밋 -> 예외시 롤백 순서로 작성 해준다.

  • 리소스를 닫는 과정 예외도 잊지 말아준다.

  • 주의 해야할점은 리소스를 닫는 부분인데 '커넥션 풀' 사용시 '수동커밋' 모드로 풀에 그대로 들어가기때문에 다음 사용시 그 커넥션을 사용할경우 문제가 되기때문에 '자동커밋'으로 설정해준뒤 닫아준다.

Test code

  • 이러면 문제없이 잘 동작한다

  • 하지만 한눈에봐도 반복코드, 코드의 복잡성, 가독성도 많이 떨어진다. 이것을 스프링에서는 어떻게 해결했는지 알아보자

profile
호주쉐프에서 개발자까지..

0개의 댓글