Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- 메서드
- continue문
- 인텔리제이 한글 깨짐 해결법
- function
- Java
- 시스템 환경 변수 편집
- multi-threading
- While
- 형 변환
- 메서드 오버로딩
- 인텔리제이 기초 설정
- 반복문
- 연관관계
- 집합관계
- OPP개념
- 상수
- for문
- 포함관계
- 접근제어지시자
- java변수
- Thread
- Java데이터 타입
- this예약어
- JAVA기초
- IntelliJ IDEA
- 자바 멀티스레딩
- JAVA객체지향
- 컴파일
- 생성자
- break문
Archives
- Today
- Total
최원종의 개발 블로그
V3-2 게시글 상세보기 (연관관계 기본 활용) 본문

Board 코드
@ManyToOne(fetch = FetchType.EAGER)
// @OneToMany
// @OneToOne
@JoinColumn(name = "user_id") // 외래키 컬럼명 표시 됨
private User user;
코드 분석
① @ManyToOne(fetch = FetchType.EAGER)
연관된 데이터를 어느 시점에 가져올지 결정하는 로딩 전략.
EAGER (즉시 로딩): 게시글(Board)을 조회할 때, JPA가 Join 쿼리를 사용해서 작성자(User) 정보까지 한 번에 다 들고옴.
LAZY (지연 로딩): 게시글만 먼저 가져오고,
나중에 board.getUser()를 호출해서 실제 데이터가 필요한 순간에 DB에 추가 쿼리를 날림.
② @JoinColumn(name = "user_id")
외래키(FK)를 관리하는 주인임을 나타냄.
name = "user_id"는 DB 테이블에 생성될 컬럼명을 지정하는 것.
만약 이걸 생략하면 user_id가 기본값으로 들어가지만, 명시적으로 적어주는 것이 유지보수에 좋음.
게시글 상세 보기 요청 조회 코드
// 게시글 상세보기 요청 (조회) (필수값 기본키로 조회)
public Board findById(Integer id) {
// 영속성 컨텍스트를 사용하기 위해
// 1. 엔티티 매니저에서 제공하는 메서드를 활용 방법
Board board = em.find(Board.class, id);
// 2. JPQL 문법으로 Board 를 조회 하는 방법
// String jpql = """
// SELECT b FROM Board b WHERE b.id = :id
// """;
// return em.createQuery(jpql, Board.class)
// .setParameter("id", id)
// .getSingleResult();
return board;
}
EAGER와 LAZY 차이
EAGER (즉시 로딩): "데이터를 조회할 때 연관된 객체까지 한꺼번에 다 가져온다."
LAZY (지연 로딩): "연관된 객체는 일단 비워두고(프록시), 실제로 사용할 때 DB에서 가져온다."
@ManyToOne(fetch = FetchType.EAGER)
Hibernate:
select
b1_0.id,
b1_0.content,
b1_0.created_at,
b1_0.title,
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.password,
u1_0.username
from
board_tb b1_0
left join
user_tb u1_0
on u1_0.id=b1_0.user_id
where
b1_0.id=?
@ManyToOne(fetch = FetchType.LAZY)
Hibernate:
select
b1_0.id,
b1_0.content,
b1_0.created_at,
b1_0.title,
b1_0.user_id
from
board_tb b1_0
where
b1_0.id=?
EAGER와 LAZY 상세 분석표
| 구분 | EAGER (즉시 로딩) | LAZY (지연 로딩) |
| 개념 | 엔티티 조회 시 연관된 객체를 함께 조회 | 연관된 객체를 실제 사용할 때 조회 |
| 조회 방식 | JOIN을 사용하여 한 번에 쿼리 실행 | 프록시(Proxy) 객체로 조회 후 필요시 쿼리 실행 |
| 쿼리 발생 시점 | em.find() 호출 시점 | obj.getRelation().getName() 호출 시점 |
| 연관관계 기본값 | @ManyToOne, @OneToOne | @OneToMany, @ManyToMany |
| 장점 | 연관 데이터를 항상 함께 사용할 때 편리함 | 불필요한 조인을 방지하여 성능 최적화에 유리 |
| 단점 | 예상치 못한 복잡한 조인과 성능 저하 유발 | 연관 객체 사용 시마다 추가 쿼리 발생 (N+1 고려 필요) |
detail-mustache 코드
{{> layout/header}}
<div class="container p-5">
<!-- 수정삭제버튼 섹션 -->
<!-- d-flex justify-content-end: 버튼들을 오른쪽 정렬 -->
<div class="d-flex justify-content-end">
<!--
수정 버튼: GET 방식으로 수정 폼 페이지로 이동
{{! board.id}}: 현재 게시글의 ID를 URL에 포함
RESTful URL 패턴: /board/{id}/update-form
-->
<a href="/board/{{board.id}}/update-form" class="btn btn-warning me-1">수정</a>
<!--
삭제 버튼: POST 방식으로 삭제 요청
form을 사용하는 이유: DELETE 동작은 GET이 아닌 POST/DELETE 방식 사용
RESTful URL 패턴: /board/{id}/delete
-->
<form action="/board/{{board.id}}/delete" method="post">
<button class="btn btn-danger">삭제</button>
</form>
</div>
<!-- 작성자 정보 표시 -->
<div class="d-flex justify-content-end">
<!-- {{! board.username}}: Board 객체의 getUsername() 메서드 호출 -->
<b>작성자</b> : {{board.user.username}}
</div>
<!-- 게시글 내용 섹션 -->
<div>
<!-- 게시글 제목 -->
<h2><b>{{board.title}}</b></h2>
<hr />
<!-- 게시글 본문 -->
<div class="m-4 p-2">
<!--
{{! board.content}}: 게시글 내용 출력
HTML 태그가 포함된 내용은 {{! board.content}} 형태로 사용 (이스케이프 해제)
보안상 사용자 입력 내용은 기본적으로 HTML 태그를 이스케이프 처리
-->
{{board.content}}
</div>
</div>
<!-- 댓글 섹션 (향후 구현 예정) -->
<div class="card mt-3">
<!-- 댓글 등록 폼 -->
<div class="card-body">
<!--
댓글 등록 폼: POST 방식으로 댓글 저장
향후 댓글 기능 구현시 사용할 예정
현재는 정적 HTML로만 구성
-->
<form action="/reply/save" method="post">
<textarea class="form-control" rows="2" name="comment" placeholder="댓글을 입력하세요"></textarea>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
<!-- 댓글 목록 헤더 -->
<div class="card-footer">
<b>댓글리스트</b>
</div>
<!-- 댓글 목록 (현재는 정적 더미 데이터) -->
<div class="list-group">
<!-- 댓글 아이템 1 -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<!-- 댓글 작성자 배지 -->
<div class="px-1 me-1 bg-primary text-white rounded">cos</div>
<!-- 댓글 내용 -->
<div>댓글 내용입니다</div>
</div>
<!-- 댓글 삭제 버튼 -->
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
<!-- 댓글 아이템 2 -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">ssar</div>
<div>댓글 내용입니다</div>
</div>
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
</div>
</div>
</div>
{{> layout/footer}}'Spring boot 입문' 카테고리의 다른 글
| V3-4 회원가입(사용자 등록과 JPA 영속성 활용) (0) | 2026.05.12 |
|---|---|
| V3-3 게시글 목록보기(연산관계로 작성자 정보 표시) (0) | 2026.05.11 |
| V3 (사용자 관리 및 연관 관계 설정) -1 연관관계 설정하기 (0) | 2026.05.11 |
| V2(PersistentContext) 게시글 수정하기 - Persistence Context와 Dirty Checking 활용 (0) | 2026.05.11 |
| V2(PersistentContext) 게시글 삭제하기 - Persistence Context와 영속성 관리 (0) | 2026.05.07 |
