본문 바로가기

Study

[내일배움캠프 TIL] 10일차 - uuid, erd표기법, Transaction

728x90
반응형

오늘은 팀프로젝트를 어떻게 진행할지, 업무 분배 등등을 진행하였습니다.

어제 테이블 명세서를 작성하였는데,

many to one 이런 관계들이 계속 헷깔려서

erd 그리는 툴을 이용해서 정리해보았습니다.

그러면서 erd 표기법에 대해서도 배울 수 있었습니다.

 

UUID

1. UUID란?

  • 정의: Universally Unique Identifier (범용 고유 식별자).
  • 목적: 중앙 집중식 관리 없이도 분산 시스템에서 중복되지 않는 고유한 ID를 생성하기 위함.
  • 특징: 128비트(16바이트) 길이의 숫자이며, 보통 36글자의 문자열(예: 550e8400-e29b...)로 표현되지만 DB 성능을 위해 BINARY(16)으로 저장함.

2. 왜 사용하는가? (장점)

  • 보안: ID가 무작위라 외부에서 데이터 양이나 순서를 추측할 수 없음 (보안 강화).
  • 분산 환경: 여러 서버에서 동시에 ID를 만들어도 충돌할 확률이 사실상 0임.
  • 독립성: DB의 Auto Increment에 의존하지 않고 애플리케이션 레벨에서 ID를 미리 결정할 수 있음.

3. JPA에서 UUID 자동 생성 설정하기

JPA를 사용하면 직접 UUID.randomUUID()를 호출하지 않아도 엔티티가 저장될 때 자동으로 생성되도록 설정할 수 있습니다.

 

ERD 표기법

1. 관계의 구성 요소 (Cardinality)

선의 끝 모양은 최소 대응수최대 대응수의 조합으로 이루어집니다.

 

 

2. 식별 vs 비식별 관계 (Identifying vs Non-Identifying)

선이 실선인지 점선인지에 따라 데이터의 종속성이 결정됩니다.

  • 실선 (식별 관계):
    • 부모의 PK가 자식의 **PK(기본키)**에 포함됨.
    • 부모 없이는 자식이 존재할 수 없는 강력한 결합.
    • 예: 주차장-주차구역 (주차장이 없으면 구역도 의미 없음)
  • 점선 (비식별 관계):
    • 부모의 PK가 자식의 **FK(일반 외래키)**로만 포함됨.
    • 자식은 자신만의 PK를 따로 가짐.
    • 현대 백엔드 개발(JPA 등)에서 가장 권장되는 방식.
    • 예: 부서-직원 (부서가 없어도 직원은 존재할 수 있음)

 

-> 식별 비식별관계를 몰라서, 처음에 툴에서 식별관계로 계속 만들었는데, pk가 계속 새로 생겨서
헷깔렸습니다.

 

 

그리고 spring관련 테스트를 했는데, 

틀린부분 오답 노트 정리합니다.

 

1. 트랜잭션(Transaction)이란?

데이터베이스에서 **"더 이상 쪼갤 수 없는 업무 처리의 최소 단위"**를 말합니다. 쉽게 말해 **"전부 성공하든지, 아니면 아예 없었던 일로 하든지(All or Nothing)"**를 보장하는 작업 단위입니다.

[현실 예시: 계좌 이체] 계좌 이체는 다음 두 단계가 하나의 트랜잭션으로 묶여야 합니다.

  1. A의 잔액을 10,000원 줄인다. (성공)
  2. B의 잔액을 10,000원 늘린다. (네트워크 오류로 실패!)
  • 트랜잭션이 없다면: A의 돈만 사라지고 B는 돈을 못 받는 사고 발생.
  • 트랜잭션이 있다면: 2번이 실패하는 순간 1번도 자동으로 취소되어 A의 돈이 다시 돌아옴 (Rollback).

2. 트랜잭션의 4가지 성질 (ACID)

면접 단골 질문이니 키워드 위주로 기억해두세요.

  • Atomicity (원자성): 트랜잭션 내 작업은 하나처럼 움직여야 함. (모두 성공 or 모두 실패)
  • Consistency (일관성): 트랜잭션이 끝나도 DB의 규칙(제약 조건 등)은 유지되어야 함.
  • Isolation (격리성): 동시에 실행되는 트랜잭션들이 서로 방해하지 못하게 격리함.
  • Durability (영속성): 성공한 트랜잭션 결과는 시스템이 고장 나도 영구적으로 저장됨.

3. 스프링의 @Transactional

매번 코드로 begin, commit, rollback을 적으려면 너무 복잡하겠죠? 스프링은 이 과정을 어노테이션 하나로 해결해 줍니다.

  • 동작 원리: 메서드 위에 @Transactional을 붙이면, 스프링이 **프록시(대리인)**를 통해 앞뒤에 트랜잭션 처리 코드를 자동으로 끼워 넣어줍니다.
    • 메서드 시작 전 -> Transaction Begin
    • 메서드 성공 종료 -> Transaction Commit (실제 반영)
    • 예외(Exception) 발생 -> Transaction Rollback (취소)

4. [오답 회고] 내부 호출 시 주의사항 (Self-Invocation)

개념을 알아도 틀리기 쉬운 포인트입니다.

  • 상황: 같은 클래스 내에서 this.method()로 @Transactional 메서드를 호출.
  • 문제: 프록시(대리인)는 외부에서 호출될 때만 작동합니다. 내부 호출은 대리인을 거치지 않고 직접 원본 코드를 실행하기 때문에, 위에 설명한 트랜잭션 안전장치가 켜지지 않습니다.
  • 결과: 오류가 나도 Rollback이 되지 않아 데이터가 꼬일 수 있음.

 

안되는 상황

@Service
public class MemberService {

    // 1. 트랜잭션이 없는 일반 메서드 (외부에서 이걸 부름)
    public void signUp(String name) {
        System.out.println("== 회원가입 프로세스 시작 ==");
        
        // [문제 발생 지점] 
        // @Transactional이 붙은 메서드를 '내부'에서 직접 호출함.
        // 스프링 프록시(대리인)를 거치지 않고 원본 메서드를 바로 실행함.
        saveMemberAndPoint(name); 
    }

    // 2. 트랜잭션이 붙은 핵심 로직
    @Transactional
    public void saveMemberAndPoint(String name) {
        // DB에 회원 저장 (성공)
        System.out.println(name + " 님 정보를 DB에 저장했습니다.");

        // [에러 발생 가정] 갑작스러운 런타임 에러 발생!
        if (true) {
            throw new RuntimeException("네트워크 오류 발생!"); 
        }

        // 포인트 지급 (에러 때문에 실행 안 됨)
        System.out.println("가입 축하 1000포인트를 지급했습니다.");
    }
}

 

 

1. 문제 상황

  • 질문: @RestController 안의 메서드에 @ResponseBody를 추가로 붙이면 어떻게 되는가?
  • 정답: B) 중복이지만 동작에 문제는 없다.
  • 나의 오답 이유: 뭔가 중복되면 충돌(에러)이 날 것 같지만, 스프링은 이미 있는 기능을 한 번 더 명시한다고 해서 에러를 내뱉지는 않습니다. 다만, 불필요한 코드가 될 뿐입니다.

2. 핵심 개념: 어노테이션의 정체

@RestController는 사실 두 가지 어노테이션을 합쳐놓은 세트 메뉴와 같습니다.

@RestController = @Controller + @ResponseBody

  • @Controller: 이 클래스가 사용자의 요청을 받는 '컨트롤러'임을 선언합니다.
  • @ResponseBody: 메서드가 반환하는 값을 '뷰(HTML)'로 찾지 않고, 데이터(JSON 등) 그대로 응답 바디에 담겠다는 뜻입니다.

3. 왜 에러가 안 날까?

이미 클래스 레벨에서 @RestController를 붙였다는 것은, **"이 클래스 안의 모든 메서드는 데이터를 반환한다(@ResponseBody 적용)"**라고 미리 선언한 것과 같습니다.

그 상태에서 메서드에 @ResponseBody를 또 붙이는 것은:

  • "이 집은 모든 메뉴가 매워요"라고 써 붙인 식당에서,
  • 특정 메뉴 옆에 "이건 매운 메뉴입니다"라고 또 써놓은 것과 같습니다.
  • 손님이 혼란스러울 수는 있어도 요리하는 데는 아무 문제가 없죠.

 

 

 

반응형