DAO 설계
데이터베이스 접근하기 위한 로직을 관리하는 객체인 DAO, 구성하는 방법에 대해 알아보겠습니다.
DAO(Data Access Object)
- 데이터베이스에 접근하기 위한 로직을 관리하기 위한 객체이다.
- 비즈니스 로직의 동작 과정에서 데이터를 조작하는 기능을 수행한다.
- 하지만, Spring Data JPA에서 DAO의 개념은 리포지토리(Repository)가 대체한다.
DAO 클래스 생성
- DAO 클래스는 일반적으로 '인터페이스-구현체' 구성으로 생성한다.
- DAO 클래스는 의존성 결합을 낮추기 위한 디자인 패턴이며, 서비스 레이어에 DAO 객체를 주입받을 때 인터페이스를 선언하는 방식으로 구성할 수 있다.
ProductDao 구성
package com.springboot.jpa.data.dao;
import com.springboot.jpa.data.entity.Product;
public interface ProductDao {
Product insertProduct(Product product);
Product selectProduct(Product product);
Product updateProductName(Long number, String name) throws Exception;
void deleteProduct(Long number) throws Exception;
}
- 일반적인 설계 원칙에서 엔티티 객체는 데이터베이스에 접근하는 계층에서만 사용하도록 정의한다.
- 다른 계층으로 데이터를 전달 할 시에는 DTO 객체를 사용한다.
- 사람마다 견해 차이가 있으므로 각자 정해진 원칙에 따라 진행하는 것이 좋다.
ProductDaoImpl 구성
@Component
@RequiredArgsConstructor
public class ProductDaoImpl implements ProductDao{
private final ProductRepository productRepository;
@Override
public Product insertProduct(Product product) {
return null;
}
@Override
public Product selectProduct(Product product) {
return null;
}
@Override
public Product updateProductName(Long number, String name) throws Exception {
return null;
}
@Override
public void deleteProduct(Long number) throws Exception {
}
}
- ProductDaoImpl 클래스를 @Bean으로 등록하려면 @Componet 또는 @Service 어노테이션을 지정해야한다.
- 빈으로 등록된 객체는 다른 클래스가 인터페이스를 가지고 의존성을 주입받을 때 이 구현체를 찾아 주입한다.
- 리포지토리를 정의하고 생성자(@RequiredArgsConstructor)를 통해 의존성을 주입받으면 된다.
insertProduct() 메서드 구성
@Override
public Product insertProduct(Product product) {
Product savedProduct = this.productRepository.save(product);
return savedProduct;
}
- JPA에서 기본 메서드를 제공하므로 save 메서드를 활용할 수 있다.
selectProduct() 메서드 구성
@Override
public Product selectProduct(Long number) {
Product selectedProduct = this.productRepository.getById(number);
return selectedProduct;
}
- 리포지토리에서 단건 조회를 위한 기본 메서드
- getById()
- 내부적으로 EntityManager의 getReference() 메서드를 호출한다.
- getReference() 메서드를 호출하면 프록시 객체를 리턴한다.
- 실제 쿼리는 프록시 객체를 통해 최초로 데이터에 접근하는 시점에 실행된다.
- 데이터가 존재하지 않는 경우, EntityNotFoundException이 발생한다.
- findById()
- 내부적으로 EntityManager의 find() 메서드를 호출한다.
- 영속성 컨텍스트의 캐시에서 값을 조회한 후 존재하지 않는다면 실제 데이터베이스에서 데이터를 조회한다.
- 리턴 값으로 Optional 객체를 전달한다.
- getById()
updateProductName() 메서드 구성
@Override
public Product updateProductName(Long number, String name) throws Exception {
Optional<Product> productId = this.productRepository.findById(number);
Product updatedProduct;
if (productId.isPresent()) {
Product product = productId.get();
product.setName(name);
product.setUpdatedAt(LocalDateTime.now());
updatedProduct = this.productRepository.save(product);
} else {
throw new Exception();
}
return updatedProduct;
}
- JPA는 값을 갱신할 때 update 키워드를 사용하지 않는다.
- 영속성 컨텍스트를 활용해 값을 갱신하는데, find() 메서드를 통해 값을 가져오면 가져온 객체가 영속성 컨텍스트에 추가된다.
- 영속성 컨텍스트가 유지되는 상황에서 객체의 값을 변경하고 다시 save()를 실행하면 JPA에서는 더티 체크(Dirty Check) 라고 하는 변경 감지를 수행한다.
[참고] SimpleJpaRepository의 save() 메서드
- @Transactional 어노테이션이 선언되어 있다.
- 메서드 내 작업을 마칠 경우 자동으로 flush() 메서드가 실행된다.
- 이 과정에서 변경이 감지되면 대상 객체에 해당하는 데이터베이스 레코드를 업데이트하는 쿼리가 실행된다.
deleteProduct() 메서드 구성
@Override
public void deleteProduct(Long number) throws Exception {
Optional<Product> selectedProduct = this.productRepository.findById(number);
if (selectedProduct.isPresent()) {
Product product = selectedProduct.get();
this.productRepository.delete(product);
} else {
throw new Exception();
}
}
- 삭제하고자 하는 레코드와 매핑된 영속 객체를 영속성 컨텍스트에 가져와야한다.
- findById() 메서드를 통해 객체를 가져오고, delete() 메서드를 통해 해당 객체 삭제 요청을 한다.
[참고] SimpleJpaRepository의 delete() 메서드
- delete() 메서드로 전달받은 엔티티가 영속성 컨텍스트에 있는지 파악하고, 해당 엔티티를 영속화하는 작업을 거쳐 데이터베이스의 레코드와 매핑한다.
- 매핑된 영속 객체를 대상으로 삭제 요청을 수행하는 메서드를 실행해 작업을 하고, 커밋(commit) 단계에서 삭제한다.
Summary
리포지토리를 활용하기 위한 DAO 클래스 구성하는 방법에 대해 알아보았다.
리포지토리 생성
- Entity를 매개변수로 이용하여 save() 메서드를 이용한다.
리포지토리 조회
- getById() : 프록시 객체를 리턴
- findById() : Optional 객체를 리턴
리포지토리 수정
- find() 메서드 활용 -> get() 메서드로 객체를 가져온다 -> 값 수정 -> save() 메서드 실행
리포지토리 삭제
- find() 메서드 활용 -> get() 메서드로 객체를 가져온다 -> delete() 메서드 실행
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
Service, Controller 클래스 생성 및 메서드 구현 (0) | 2023.11.03 |
---|---|
JPA Repository 인터페이스 생성과 사용 방법 (0) | 2023.11.02 |
엔티티(Entity) 설계 및 클래스 구성 (0) | 2023.11.02 |
댓글