⬜ 섹션8 데이터 접근 기술 - 활용 방안
◼️ 스프링 데이터 JPA 예제와 트레이드 오프
중간에 JpaItemRepository가 어뎁터 역할을 해준다.
ItemService가 사용하는 인터페이스(ItemRepository)를 그대로 유지할 수 있다.
클라이언트인 ItemService 코드를 변경하지 않아도된다.하지만...전체 구조가 복잡하고 사용클래스도 많아졌다!!!
위처럼 ItemService에서 직접 스프링데이터JPA 리포지토리를 직접참조할 수 있다.
하지만 이경우 ItemService 코드를 변경해야 한다.
🟢 트레이드 오프
- 안정성: DI, OCP를 지키기 위해 어댑터를 도입하고, 더 많은 코드를 유지한다.
- 개발 편리성: 어댑터를 제거하고 구조를 단순하게 가져가지만, DI, OCP를 포기하고, ItemService 코드를 직접 변경한다.
◼️ 실용적 구조
스프링 데이터 JPA 기능을 최대한 살리면, Querydsl도 편리하게 사용할 수 있는 구조를 만들어보자.
- 스프링 데이터 JPA: 기본 CRUD와 단순 조회
- Querydsl: 복잡한 조회 쿼리
package hello.itemservice.repository.v2;
import hello.itemservice.domain.Item;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ItemRepositoryV2 extends JpaRepository<Item, Long> {
// 추가로 단순한 조회 쿼리들을 추가해도 된다.
}
ItemQueryRepositoryV2는 Querydsl을 사용해서 복잡한 쿼리 문제를 해결한다.
package hello.itemservice.repository.v2;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import hello.itemservice.domain.Item;
import hello.itemservice.repository.ItemSearchCond;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManager;
import java.util.List;
import static hello.itemservice.domain.QItem.item;
@Repository
public class ItemQueryRepositoryV2 {
private final JPAQueryFactory query;
public ItemQueryRepositoryV2(EntityManager em) {
this.query = new JPAQueryFactory(em);
}
public List<Item> findAll(ItemSearchCond cond) {
return query.select(item)
.from(item)
.where(
maxPrice(cond.getMaxPrice()),
likeItemName(cond.getItemName()))
.fetch();
}
private BooleanExpression likeItemName(String itemName) {
if (StringUtils.hasText(itemName)) {
return item.itemName.like("%" + itemName + "%");
}
return null;
}
private BooleanExpression maxPrice(Integer maxPrice) {
if (maxPrice != null) {
return item.price.loe(maxPrice);
}
return null;
}
}
package hello.itemservice.service;
import hello.itemservice.domain.Item;
import hello.itemservice.repository.ItemSearchCond;
import hello.itemservice.repository.ItemUpdateDto;
import hello.itemservice.repository.v2.ItemRepositoryV2;
import hello.itemservice.repository.v2.ItemQueryRepositoryV2;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
@Transactional
public class ItemServiceV2 implements ItemService {
private final ItemRepositoryV2 itemRepositoryV2;
private final ItemQueryRepositoryV2 itemQueryRepositoryV2;
@Override
public Item save(Item item) {
return itemRepositoryV2.save(item);
}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
Item findItem = findById(itemId).orElseThrow();
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
@Override
public Optional<Item> findById(Long id) {
return itemRepositoryV2.findById(id);
}
@Override
public List<Item> findItems(ItemSearchCond cond) {
return itemQueryRepositoryV2.findAll(cond);
}
}
◼️ 다양한 데이터 접근 기술 조합
- JPA, 스프링 데이터 JPA, Querydsl을 기본으로 사용
- 만약 복잡한 쿼리를 써야 하면 JdbcTemplate이나 MyBatis를 함께 사용
🟢트랜잭션 매니저
- JPA, 스프링 데이터 JPA, Querydsl: JpaTransactionManager
- JdbcTemplate,MyBatis: DataSourceTransactionManager ( 내부에서 JDBC를 직접 사용 )
🤔트랜잭션 매니저가 다른데 트랜잭션을 하나로 묶으려면!?
😉 JPA기술도 내부에서는 DataSource와 JDBC 커넥션을 사용하기때문에, JpaTransactionManager DataSourceTransactionManager 제공기능도 대부분 제공한다!
따라서 JpaTransactionManager하나만 스프링 빈에 등록하면 JPA, JdbcTemplate, MyBatis 모두를 하나의 트랜잭션으로 묶어서 사용할 수 있다.
'Spring' 카테고리의 다른 글
[Spring] 스프링 DB 2편 - 데이터 접근 핵심 원리 섹션10 스프링 트랜잭션 전파1 - 기본 (0) | 2024.07.10 |
---|---|
[Spring] 스프링 DB 2편 - 데이터 접근 핵심 원리 섹션9 스프링 트랜잭션 이해 (0) | 2024.07.08 |
[Spring] 스프링 DB 2편 - 데이터 접근 활용 기술 섹션6 데이터 접근 기술 - Querydsl (0) | 2024.07.07 |
[Spring] 스프링 DB 1편 - 데이터 접근 핵심 원리 섹션5,6 예외 & 스프링과 문제 해결 - 예외 처리, 반복 (0) | 2024.06.11 |
[Spring] 스프링 DB 1편 - 데이터 접근 핵심 원리 섹션4 스프링과 문제 해결 - 트랜잭션 (0) | 2024.06.05 |