오늘은 팀프로젝트를 어떻게 진행할지, 업무 분배 등등을 진행하였습니다.
어제 테이블 명세서를 작성하였는데,
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)"**를 보장하는 작업 단위입니다.
[현실 예시: 계좌 이체] 계좌 이체는 다음 두 단계가 하나의 트랜잭션으로 묶여야 합니다.
- A의 잔액을 10,000원 줄인다. (성공)
- 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를 또 붙이는 것은:
- "이 집은 모든 메뉴가 매워요"라고 써 붙인 식당에서,
- 특정 메뉴 옆에 "이건 매운 메뉴입니다"라고 또 써놓은 것과 같습니다.
- 손님이 혼란스러울 수는 있어도 요리하는 데는 아무 문제가 없죠.
'Study' 카테고리의 다른 글
| [내일배움캠프 TIL] 12일차 - JWT, Auth 구현(회원가입 로그인) (0) | 2026.04.21 |
|---|---|
| [내일배움캠프 TIL] 11일차 - Controller 단에서 로직 분리 실습 2 (0) | 2026.04.20 |
| [내일배움캠프 TIL] 9일차 - Controller 단에서 로직 분리 실습 1 (0) | 2026.04.16 |
| [내일배움캠프 TIL] 8일차 - Spring 정리. 빈스코프 (0) | 2026.04.15 |
| [내일배움캠프] MSA 강의 총 정리 (0) | 2026.04.15 |