오늘 진행한 학습 요약
1. 스탠다드반 강의 (트랜잭션)
- 트랜잭션이란?
- ACID
- 전파 속성 (Propagation)
- 격리 수준 (Isolation)
- 스프링 트랜잭션 어노테이션
- 트랜잭션 상태
- 스프링의 롤백
- 트랜잭션 내부 호출 문제
2. 아웃소싱 프로젝트
- 개발 프로세스 가이드
- 트러블 슈팅
3. 알고리즘 코드카다 Day51 (작성 생략)
CodingTest Git-hub 링크 : https://github.com/chews26/CodingTest
학습 정리
1. 스탠다드반 강의 (트랜잭션)
트랜잭션이란?
- Trans + Action의 합성어
- 교환을 하는 행동을 말하는 것으로 물물교환을 의미
- 1960년대 초 IBM은 컴퓨터 업계에서 트랜잭션이라는 개념을 정리하고 발전
- 지금의 DB와 프로그래밍 언어에 쓰이는 트랜잭션도 그 뿌리는 IBM이 정립한 트랜잭션의 개념에 두고 있음
ACID
- 하나의 트랜잭션이 발생했을 때 안전성을 보장하기 위한 중요한 4가지 속성
-
Atomicity (원자성)모든 작업이 성공하거나 아무 작업도 일어나지 않음Consistency (일관성)하나의 트랜잭션 끝난 뒤에도 모든 상태는 이전과 같이 유효Isolation (격리성)모든 트랜잭션은 다른 트랜잭션으로부터 독립적Durability (지속성)하나의 트랜잭션이 완료되었다면 영구적으로 저장
- 이 개념은 1970년대 말에 짐 그레이(Jim Gray)가 신뢰할 수 있는 트랜잭션 시스템의 이러한 특성으로 정의
- 자동으로 이들을 수행하는 기술을 개발
전파 속성 (Propagation)
- 트랜잭션에서 전파 속성은 하나의 트랜잭션이 시작된 상태에서, 또 다른 트랜잭션이 시작되었을 때 이를 어떻게 처리할지를 정의
-
종류기존 트랜잭션 X기존 트랜잭션 O적용 사례REQUIRED새 트랜잭션 생성기존 트랜잭션에 참여기본값. 대부분의 비지니스 로직REQUIRES_NEW새 트랜잭션 생성기존 트랜잭션 일시중단, 새로운 트랜잭션 생성독립적인 작업 처리SUPPORTS트랜잭션 없이 진행기존 트랜잭션 참여트랜잭션이 필수가 아닌 작업NOT_SUPPORTED트랜잭션 없이 진행기존 트랜잭션 일시중단, 트랜잭션 없이 진행로그 저장 등 트랜잭션과 독집적인 작업MANDATORYIllegalTransactionStateException 발생기존 트랜잭션 참여트랜잭션 내부에서만 호출 가능한 메소드NEVER트랜잭션 없이 진행IllegalTransactionStateException 발생외부 시스템 호출시NESTED새 트랜잭션 생성중첩 트랜잭션 생성부분적으로 롤백 가능한 작업
격리 수준 (Isolation)
- 트랜잭션 격리 수준은 여러 트랜잭션이 동시 발생할 때 어떻게 데이터 일관성을 보장 할지를 정의하는 것
-
Isolation Level설명방지되는 문제적용 사례READ_UNCOMMITTED커밋되지 않은 데이터도 읽을 수 있음없음데이터 정확성보다 성능이 중요한 경우READ_COMMITTED커밋된 데이터만 읽을 수 있음Dirty Read대부분의 애플리케이션 기본 설정REPEATABLE_READ같은 트랜잭션 내에서 읽은 데이터가 변경되지 않음Dirty Read, Non-repeatable Read은행 계좌 조회와 같은 데이터 무결성 요구SERIALIZABLE트랜잭션이 순차적으로 실행, 가장 엄격한 격리 수준Dirty Read, Non-repeatable Read, Phantom Read금융 시스템의 이체 작업 등 높은 신뢰성이 필요한 경우
-
수준Dirty ReadNon-repeatable ReadPhantom ReadREAD_UNCOMMITTEDOOOREAD_COMMITTEDXOOREPEATABLE_READXXOSERIALIZABLEXXX
스프링 트랜잭션 어노테이션
- 스프링에는 2가지 @Tx 어노테이션이 존재
- Java에서 지원하는 어노테이션
- 스프링이 지원하는 어노테이션
- 두 가지는 트랜잭션의 기본 기능은 모두 동일하게 지원
- 하지만 스프링의 어노테이션이 더 많은 기능을 지원
-
옵션설명isolationTransaction의 Isolation level을 설정한다.labelTransaction label을 설정한다.noRollbackFortransaction rollback 처리가 되지 않아야 할 예외 클래스를 명시한다.noRollbackForClassNametransaction rollback 처리가 되지 않아야 할 예외 클래스 이름을 명시한다.propagationTransaction Propagation 타입을 설정한다.readOnlyTransaction을 readOnly로 설정한다.rollbackFortransaction rollback이 되어야하는 예외 클래스를 명시한다.rollbackForClassNametransaction rollback이 되어야하는 예외 클래스 이름을 명시한다.timeoutTransaction의 Timeout을 설정한다. (단위 : 초,seconds)timeoutStringTransaction의 Timeout을 설정한다. (단위 : 초,seconds)transactionManager특정 Transaction의 qualifier value를 설정한다.valuetransactionManager의 alias(별칭)을 설정한다.
트랜잭션 상태
- 활동 상태 (active) : 초기 상태, 트랜잭션이 실행 중일 때 가지는 상태
- 부분 완료 상태 (partically committed) : 마지막 명령문이 실행된 후에 가지는 상태
- 완료 상태 (committed) : 트랜잭션이 성공적으로 완료된 후 가지는 상태
- 실패 상태 (failed) : 정상적인 실행이 더 이상 진행될 수 없을 때 가지는 상태
- 철회 상태 (aborted) : 트랜잭션이 취소되고 데이터베이스가 트랜잭션 시작 전 상태로 환원된 상태
스프링의 롤백
- Atomicity(원자성) 속성
- 모든 작업이 성공하거나 아무 작업도 일어나지 않음
- 이 속성에 의하면 트랜잭션 중에 실패하면 반드시 아무 작업도 일어나지 않아야함
- 즉 기존 완료된 작업이 Rollback이 되어야 한다는 의미.
- 실패는 Exception 상황
- Tx 내부에서 Exception 발생 → Atomicity 보장 필요 → Rollback
- Unchecked/Checked Exception에 따라 각각 처리가 다름
- 스프링의 롤백 기본 동작
-
조건롤백 여부설명Unchecked Exception (RuntimeException 또는 Error 계열)O기본적으로 스프링 트랜잭션은 RuntimeException 또는 Error 발생 시 롤백 처리Checked Exception (Exception을 상속하고 RuntimeException이 아닌 예외)XChecked Exception은 기본적으로 롤백 트리거가 아님 (명시적으로 설정해야 롤백 가능)@Transactional의 rollbackFor 설정에 포함된 Checked Exception 발생OrollbackFor 속성에 지정된 Checked Exception은 롤백 트리거로 작동try-catch로 RuntimeException을 처리한 경우ORuntimeException 발생 시 이미 롤백 상태로 마킹되므로 catch 처리 여부와 무관하게 롤백try-catch로 Checked Exception을 처리한 경우XChecked Exception은 기본적으로 롤백되지 않으며 catch로 처리 시 트랜잭션 상태 유지@Transactional의 noRollbackFor 설정에 포함된 Exception 발생XnoRollbackFor 속성에 지정된 Exception은 롤백하지 않음Transactional 내부에서 catch 후 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(false) 호출Xcatch 이후 롤백 플래그를 false로 명시적으로 변경 시 롤백 방지Transaction이 외부 트랜잭션에서 관리되는 경우 (Propagation.REQUIRED)외부 트랜잭션에 따름내부 트랜잭션에서 롤백 마킹이 되어도 외부 트랜잭션의 최종 상태에 의존Transaction이 새 트랜잭션 (Propagation.REQUIRES_NEW)인 경우내부 트랜잭션에 따름내부 트랜잭션의 롤백은 외부 트랜잭션에 영향을 주지 않음
-
트랜잭션 내부 호출 문제
- 스프링은 트랜잭션을 적용하기 위해서는 반드시 프록시 객체를 통해야 함
- 프록시 객체는 우리가 Contoller, @Service, @Repository와 같은 어노테이션을 적용하면 사용할 수 있는 것
- 이 프록시 객체를 통해 메소드 호출이 일어나면 메소드가 호출 되는 시점, 종료되는 시점에 각각 트랜잭션 처리가 되는 원리
2. 아웃소싱 프로젝트
개발 프로세스 가이드
- 0단계 : 목표 정하기! (Growth Mindset)
- 배달의 인간 (배달 어플 만들기)
- 1단계 : 팀 노션 작성하기!
- 프로젝트 소개
- 기획관련메모
- WBS & Tasks 작성
- 깃헙 커밋큐칙 작성
- 2단계 : 프로젝트 아이디어 구상하기!
- 배달의 인간은 사장님과 고객을 연결하는 통합 배달 플랫폼!
- 3단계 : 와이어프레임 작성하기!
- 4단계 : ERD 작성하기!
- 5단계 : API 명세 작성하기!
- 6단계 : S.A 작성 및 피드백 받기!
- 7단계 : 본격적인 백엔드 개발하기!
- 로그인, 유저관리, 인증/인가 부분을 담당!
- 8단계 : 테스트 및 버그 수정하기!
- 진행중...
👾 트러블 슈팅
- 🤔 문제
- StoreRepository에서 쿼리 메서드 네이밍 규칙과 엔티티 매핑 정보 불일치로 인한 Spring이 실행이 불가했다!
Optional<Store> findByMember_IdAndStore_Id(Long userId, Long storeId);
- 😎 해결방법
- 팀원과 상황을 즉시 공유하였다. 팀원 한분이 문제를 해결할 수 있는 방법을 제시해 주시고 코드 수정을 도와주셨다!
- JPA는 연관 관계(@ManyToOne, @OneToMany)를 사용하는 필드에서 하위 속성을 탐색할 때 필드명을 정확히 알아야하는데 자동 생성된 메서드 네이밍에서 잘못된 필드명을 사용하면 오류가 발생하기 때문에 메서드 네이밍과 다르다면 명시적으로 쿼리를 작성하여 해결해야 했다
- JPA가 네이밍 규칙을 기반으로 쿼리를 자동 생성하지 않도록 명시적으로 쿼리 작성하여 문제 해결하였다
- 관련 링크
@Query("SELECT s FROM Store s WHERE s.member.userId = :memberId AND s.id = :storeId")
Optional<Store> findByMember_IdAndStore_Id(@Param("memberId") Long memberId, @Param("storeId") Long storeId);