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
- Java
- this예약어
- java변수
- JAVA기초
- 상수
- break문
- 메서드
- 형 변환
- 접근제어지시자
- 반복문
- 컴파일
- 집합관계
- Thread
- While
- OPP개념
- multi-threading
- 생성자
- for문
- IntelliJ IDEA
- 시스템 환경 변수 편집
- 메서드 오버로딩
- 포함관계
- 인텔리제이 한글 깨짐 해결법
- 인텔리제이 기초 설정
- JAVA객체지향
- Java데이터 타입
- 연관관계
- continue문
- function
- 자바 멀티스레딩
Archives
- Today
- Total
최원종의 개발 블로그
V2(PersistentContext) 게시글 수정하기 - Persistence Context와 Dirty Checking 활용 본문
Spring boot 입문
V2(PersistentContext) 게시글 수정하기 - Persistence Context와 Dirty Checking 활용
chl6698 2026. 5. 11. 09:09BoardRequest.UpdateDTO -코드 (내부 클래스 추가)
package com.tenco.blog.board;
import lombok.Builder;
import lombok.Data;
// 요청 데이터를 담는 DTO 클래스
// 컨트롤러.. 비즈니스 .. 데이터 계층 사이에서 데이터 전송 역할 객체
public class BoardRequest {
@Data
@Builder
public static class SaveDTO {
private String username;
private String title;
private String content;
// 편의 기능 설계 가능
// DTO 에서 Entity로 변환해주는 편의 메서드
public Board toEntity() {
return Board.builder()
.username(username)
.title(title)
.content(content)
.build();
}
}
// 내부 정적 클래스 게시글 수정 DTO 설계
@Data
public static class UpdateDTO {
private String username;
private String title;
private String content;
// 게시글 수정시 유효성 검사 편의 메서드
public void validate() {
if(username == null ||username.trim().isEmpty()) {
throw new IllegalArgumentException("작정자 이름은 필수입니다");
}
if(title == null || title.trim().isEmpty()) {
throw new IllegalArgumentException("제목은 필수입니다");
}
if(content== null || content.length() < 3) {
throw new IllegalArgumentException("내용은 3글자 이상 작성해야 합니다.");
}
}
}
}
BoardController 코드 수정
@PostMapping("/board/{id}/update")
// 메세지 컨버터란 객체가 동작해서 자동으로 객체를 생성하고 값을 매핑해 준다.
public String updateProc(@PathVariable(name = "id") Integer id,
BoardRequest.UpdateDTO updateDTO) {
// 1. 유효성 검사
// username, title, content 유효성 검사
updateDTO.validate();
boardPersistRepository.updateById(id, updateDTO);
return "redirect:/board/" + id;
}
BoardPersistRepository 코드 수정
@Transactional
public void updateById(Integer id, BoardRequest.UpdateDTO updateDTO) {
// 수정시 항상 조회 먼저 확인
Board boardEntity = em.find(Board.class, id);
// em.find() 호출 수 리턴 받은 board 는 영속 상태가 되어 졌다.
if(boardEntity == null) {
throw new IllegalArgumentException("수정할 게시글을 찾을 수 없습니다 : " + id);
}
boardEntity.update(updateDTO);
// 변경 감지(Dirty Checking) 동작 됨.
// 영속 컨텍스트에 관리 되어지는 객체(엔티티)안에 조회 했을 때 기준으로 1차 캐쉬에 저장되어 짐
// 추후 1차 캐쉬에 들어가 있는 객체의(엔티티의) 변수값이 변경 되었다면 자동으로 감지 한다.
// 그냥 새로은 보드 생성
//em.persist(boardEntity);
// 앞으로 수정 기능을 만들어 줄 때 더티 체킹 동작으로 사용하자.
}
Board 코드
package com.tenco.blog.board;
import com.tenco.blog.util.MyDateUtil;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Data // get,set, toString ..
// @Entity - JPA가 이 클래스를 데이터베이스 테이블과 매핑하는 객체로 인식하게 설정
// 즉, 이 어노테이션이 있어야 JPA가 관리 함
@Entity
@Table(name = "board_tb")
@NoArgsConstructor
@AllArgsConstructor // 전체 멤벼 번수를 넣을 수 있는 생성자.
@Builder
public class Board {
// @id : 이 필드가 기본키임을 설정 함
@Id
// IDENTITY 전략: 데이터베이스게 기본 AUTO_INCREMENT 기능 사용
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String title;
private String content;
// @CreationTimestamp : 하이버네이트가 제공하는 어노테이션
// 특정 하나의 엔티티가 저장이 될 때 현재 시간을 자동으로 저장해 설정
// now() 명시할 필요 없음
// pc --> db (자동 날짜 주입)
@CreationTimestamp
private Timestamp createdAt;
// createdAt -> 포멧 하는 메서드 만들어 보기
public String getTime() {
return MyDateUtil.timestampFormat(createdAt);
}
// 수정 편의 기능 만들기
public void update(BoardRequest.UpdateDTO updateDTO) {
this.username = updateDTO.getUsername();
this.title = updateDTO.getTitle();
this.content = updateDTO.getContent();
// 더티체킹 - 변경 감지 동작 과정
// 1. 최초 조회시 영속성 컨텍스트 1차 캐쉬에 데이터를 스냅샷으로 보관 함.
// 2. 영속화된 엔티티가(board)의 멤버 변수값이 변경이 된다면
// 1차에서 보관했던 값과 2차에서 수정된 필드값을 비교 함.
// 3. 변화가 발생이 되었다면 트랜잭션 커밋 시점에 변경된 필드값 UPDATE 쿼리 자동 생성
// 4. 물리적은 DB에 반영 됨.
}
}
더티 체킹(Dirty Checking)
영속 상태의 엔티티 값만 변경하면, 트랜잭션이 끝날 때 JPA가 알아서 UPDATE SQL을 실행하는 기능
더티 체킹 작동 원리
조회: DB에서 엔티티를 조회하여 영속성 컨텍스트에 넣음. (이때 스냅샷 생성)
수정: 자바 코드에서 객체의 값(setName, setAge 등)을 바꿈.
트랜잭션 커밋: 사용자가 커밋을 하면 JPA는 내부적으로 flush()를 호출.
비교: 현재 엔티티의 상태와 처음 찍어둔 스냅샷을 하나하나 비교.
SQL 실행: 이름이 바뀌었다라고 판단되면 자동으로 UPDATE 쿼리를 만들어 DB로 날림.
더티 체킹의 조건
영속 상태여야 함: 영속성 컨텍스트가 관리하지 않는 객체(비영속, 준영속)는 값을 아무리 바꿔도 JPA가 알 방법이 없음.
장바구니에 담긴 물건이어야 주인이 바뀌었는지 알 수 있는 것과 같다.
트랜잭션 안에서 일어나야 함: 보통 서비스 레이어의 메서드에 @Transactional이 붙어 있어야 한다.
트랜잭션이 끝나는 시점에 비교 작업이 시작되기 때문이다'Spring boot 입문' 카테고리의 다른 글
| V3-2 게시글 상세보기 (연관관계 기본 활용) (0) | 2026.05.11 |
|---|---|
| V3 (사용자 관리 및 연관 관계 설정) -1 연관관계 설정하기 (0) | 2026.05.11 |
| V2(PersistentContext) 게시글 삭제하기 - Persistence Context와 영속성 관리 (0) | 2026.05.07 |
| V2(PersistentContext) 게시글 상세보기 만들기 - Persistence Context와 1차 캐시 활용 (0) | 2026.05.07 |
| V2(PersistentContext) 게시글 목록 보기 - Persistence Context와 JPQL 활용 (0) | 2026.05.07 |
