1. 개요
김영한님의 '실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발' 강의를 수강하면서 개인적으로 중요하게 생각하는 핵심 부분과 새롭게 알게된 내용을 정리한 포스팅입니다
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 강의 | 김영한 - 인프런
김영한 | , 스프링 부트, 실무에서 잘 쓰고 싶다면? 깊이있는 설계와 개발을 경험해 보세요. 🚩 본 강의는 로드맵 과정입니다. 본 강의는 자바 백엔드 개발의 실전 코스를 시작하는 첫 강의입니
www.inflearn.com
2. 도메인 모델 패턴 VS 트랜잭션 스크립트 패턴
강의에서 비즈니스 로직을 어떤식으로 처리할지에 대한 2가지 설계 패턴을 소개한다.
각 패턴에 대해 정리해보자.
트랜잭션 스크립트 패턴
비즈니스 로직을 서비스 계층에 직접 구현하는 방식이다.
단순한 로직에는 효과적이지만, 비즈니스 로직이 복잡할 경우 서비스 계층이 비대해지며 그로 인해 유지보수가 어려워질 수 있다.
- 서비스 계층에서 엔티티 상태 변경 수행한다.
- 비즈니스 로직이 복잡해질수록 서비스 계층이 복잡해지는 문제가 있다.
- 간단한 예시를 위해 엔티티 클래스의 setter를 열어두었지만 setter를 모두 열어주는 것은 권장하지 않는다. => 변경감지로 인해 update 쿼리 발생
@Service
public class ItemService {
private final ItemRepository itemRepository;
@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity) {
Item item = itemRepository.findOne(itemId);
item.setName(name); // 이름 수정
item.setPrice(price); // 가격 수정
item.setStockQuantity(stockQuantity); // 재고 수정
}
}
도메인 모델 패턴
비즈니스 로직을 도메인 객체에 위임하여 서비스 계층을 단순화하는 접근법이다.
도메인 객체가 자신의 상태와 행위를 책임지고, 복잡한 비즈니스 규칙을 객체 내에 분산시켜 유지보수를 용이하게 한다.
- 도메인 객체 스스로가 자신의 상태를 변경하는 책임을 갖는다.
- 서비스 계층은 도메인 객체의 행위에 집중하여 적절한 행위를 호출함으로써 역할과 책임이 명확해진다.
- 복잡한 비즈니스 로직을 객체 내에 분산시켜 유지보수를 용이하게 한다.
@Getter
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public abstract class Item {
@Id @GeneratedValue @Column(name = "item_id") private Long id;
private String name;
private int price;
private int stockQuantity;
/**
* 상품 정보 업데이트
* @param name 상품 이름
* @param price 상품 가격
* @param stockQuantity 재고 수량
*/
public void updateItem(String name, int price, int stockQuantity) {
this.name = name;
this.price = price;
this.stockQuantity = stockQuantity;
}
}
@Service
public class ItemService {
private final ItemRepository itemRepository;
@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity) {
Item item = itemRepository.findOne(itemId);
item.updateItem(name, price, stockQuantity);
}
}
정리
하나의 애플리케이션의 내에서도 두 패턴은 공존할 수 있다.
나의 생각은 기본적으로 도메인 모델 패턴을 사용하되 아주 간단한 비즈니스 로직에는 트랜잭션 스크립트 패턴을 부분적으로 사용하는 것이 좋을 것 같다!
3. merge()의 동작 방식
merge(T entity)는 준영속 또는 비영속 상태의 엔티티를 전달받아, 동일한 식별자를 가진 엔티티를 1차 캐시(없으면 DB)에서 조회한 후, 전달받은 엔티티의 값을 복사하여 영속화 된 엔티티를 반환하는 메서드이다.
public void update(Item item) { // 식별자가 존재하는 준영속(비영속)상태의 엔티티
em.merge(item);
}
동작 과정
1. merge(T entity) 호출
2. 전달된 엔티티의 식발자 값으로 1차 캐시에서 조회
2-1. 1차 캐시에 없으면 DB에서 조회하여 1차 캐시에 저장
3. 조회된 영속 엔티티에 전달된 엔티티의 값을 복사
4. 복사된 영속 엔티티를 반환

최종적으로 트랜잭션이 종료되면, 변경감지(Dirty Checking)를 통해 복사된 영속 엔티티의 변경 사항이 감지되고, DB에 Update 쿼리를 전달한다.
'Programming > Spring' 카테고리의 다른 글
| [Spring 테스트] 테스트 간 데이터 충돌 문제 해결(@Sql 이해) (0) | 2025.07.11 |
|---|---|
| [JPA] 실전! 스프링 부트와 JPA 활용2 강의 핵심 내용 정리 (0) | 2025.07.01 |
| [SpringBoot] Spring Boot 404 응답 커스터마이징 (0) | 2025.04.03 |
| [Spring Boot] Spring Boot + InfluxDB 연동 (0) | 2025.02.06 |
| [Spring] Spring에서 비동기 @Async 이해하기 (0) | 2024.08.23 |