스프링 DB 1(김영한 강의) - 섹션 3 : 트랜잭션 이해
섹션 목적 : 트랜잭션을 이해해보자
1. 트랜잭션 - 개념이해
(1) A -> B에게 5000원을 계좌이체를 가정. 이후에 A = A - 5000, B = B + 5000이 되어야함
(2) 그런데, A - 5000후에 시스템에 문제가 발생하면, A에 5000원만 빠지는 심각한 문제가 발생
(3) 따라서, 위 두 행위는 하나의 작업 처럼 수행돼야함
(4) 트랜잭션은 이러한 하나의 작업 단위임. 하나라도 실패하면 rollback, 전부 성공하면 DB에 commit
(5) 트랜잭션의 ACID
① A(원자성) : 트랜잭션 내의 작업들은 마치 하나의 작업(원자)처럼 모두 성공 or 실패해야함
② C(일관성) : 트랜잭션 이전과 이후 DB의 상태는 유효해야함. 트랜잭션 이후에도 DB의 제약이나 규칙이 만족해야함
③ I(격리성) : 트랜잭션은 다른 트랜잭션으로부터 독립되어야함. 여러 트랜잭션이 동시에 수행되더라도, 마치 혼자 수행하는 것처럼 동작해야 함
④ D(지속성) : 트랜잭션을 성공적으로 끝내면 그 결과는 항상 기록되어야함. 중간에 문제가 발생하더라도, 로그 등을 통해서 성공한 트랜잭션을 복구해야함
2. DB 연결구조와 DB 세션
(1) 클라이언트는 DB와 연결을 요청해서 커넥션을 맺으면, DB는 이 커넥션과 연결된 세션을 만듬
(2) 앞으로 해당 커넥션으로 요청이 들어오면, 이 세션이 일을 처리함
(3) 세션이 트랜잭션을 시작 -> 커밋 or 롤백 -> 트랜잭션 종료를 수행
3. DB 락 - 개념이해
(1) 세션 1이 데이터를 수정하는 동안 세션 2에서 동시에 같은 데이터를 수정하려할 때 문제가 발생
(2) 트랜잭션이 시작되서 데이터를 수정하고 커밋 or 롤백 전에, 다른 트랜잭션에서 같은 데이터를 수정하지 못하도록 하는 것이 'DB 락' 임
(3) 다른 트랜잭션은 락을 가지고 있는 기존 트랜잭션이 커밋 or 롤백을 해서 락을 반환할 때까지 대기
(4) 무한정 대기하는 것은 아니고, 일정 시간 동안. 이러한 락 타임아웃을 설정할 수 있음
4. DB 락 - 조회
(1) 일반적인 조회 시 락을 사용하지 않음
(2) 그렇지만, 조회할 때도 락을 획득하고 싶을 때가 있음(ex. 정산 시, 아무도 데이터에 손을 못대고 하고 싶을 때)
(3) 이 때는 select for update 문을 사용하면, 조회에도 락을 획득할 수 있음
5. 트랜잭션 - 적용 1
(1) 트랜잭션 없이 단순히 계좌이체 비즈니스 로직을 구현(MemberServiceV1)
(2) MemberServiceV1은 이체 중 예외가 발생하면, memberA의 돈만 감소하는 문제가 발생
6. 트랜잭션 - 적용 2
(1) 트랜잭션은 비즈니스 로직이 있는 서비스 계층에서 시작해야 함
(2) 이유는 비즈니스 로직이 잘못되면, 해당 비즈니스 로직 작업 전체를 rollback해야하기 때문
(3) 그래서 service에서 커넥션을 얻어오고 -> 비즈니스 로직 실행 -> 커밋 or 롤백 -> 커넥션 종료해야 함
(4) 그리고 트랜잭션을 사용하는 동안에는 모두 같은 커넥션을 유지해서 사용해야 함
(5) 따라서, MemberRepositoryV2의 메소드는 service에서 생성된 Connection을 파라미터로 받아서 이 커넥션으로 작업을 수행해야 함
(6) MemberServiceV2는
① dataSource.getConnection()을 통해서 Connection을 가져오고
② connection.setAutoCommit(false)로 트랜잭션 시작
③ 이 커넥션을 파라미터로 주면서 비즈니스 로직 수행
④ 커밋 or 롤백
⑤ 커넥션 종료 순서로 흘러감
(7) 테스트를 해보면 정상적으로 동작
(8) 하지만, 서비스 계층에 DB관련 코드가 많아지면서 지저분해지고 복잡해지는 문제 발생. 따라서, 스프링이 이를 어떻게 도와주는지 다음시간에 공부
이펙티브 자바 - 아이템 4 : 인스턴스화를 막으려거든 private 생성자를 사용하라
- 단순히 static 메서드와 static 필드만을 담은 class를 만들고 싶을 때가 있음
- 이러한 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계된 것이 아님
- 따라서, 인스턴스화를 막아야함
- 그 방법 중 클래스를 추상클래스로 만드는 방법이 있는데, 이는 인스턴스화를 막을 수 없음
- 이유는 이 클래스를 상속해서 자식 클래스를 통해 인스턴스를 만들 수 있기 때문임
- 그리고, 사용자는 abstract을 보고 '상속해서 사용하라는 건가?'라고 착각할 수 있음
- 따라서, private 생성자를 사용하면 문제를 해결할 수 있음
- private 생성자를 사용하면, 사용자가 보기에 직관성이 떨어지므로 앞에다 '인스턴스화 방지용' 주석 처리
- private 생성자는 또한 상속이 불가능함. 자식에서 spuer()을 할 수 없기 때문
코테준비
1. 프로그래머스 - 피로도
- 모든 던전을 다 탐색해보는 완전탐색 문제
2. 프로그래머스 - 전력망을 둘로 나누기
- 처음에는 모든 전력망을 한번씩 끊어보면서, dfs를 돌려서 찾았음
- 이 후, 다른 사람의 풀이를 보고 해당 노드의 자식 갯수를 구해서 풀 수 있는 방법으로 바꿈(트리의 성질을 이용)
3. 프로그래머스 - 전화번호 목록
- 전화번호를 HashSet에 넣고, 각 전화번호의 접두사를 잘라서 HashSet에 있는지 확인하는 방법으로 풀이
4. 프로그래머스 - 의상
- 의상의 종류에 따라 HashMap에 담고, 모든 가짓수를 수학적으로 계산해서 풀이
오늘 하루 고생했다~
'TIL(Today I Learned)' 카테고리의 다른 글
2023.06.29 (0) | 2023.06.30 |
---|---|
2023.06.28 (0) | 2023.06.29 |
2023.06.26 (0) | 2023.06.26 |
2023.06.23 (0) | 2023.06.23 |
2023.06.22 (0) | 2023.06.22 |