참고
스프링 데이터 JPA 예제와 트레이드 오프
NOTE
지금까지 구성해온 스프링 데이터 JPA 구성을 다시 한번보자.
•
JpaItemRepositoryV2가 어댑터 역할
◦
ItemServive가 사용하는 ItemRepository 인터페이스를 그대로 유지할 수 있다.
◦
클라이언트인 ItemService를 변경하지 않아도 되는 장점이 있다.
•
그런데 SpringDataJpaItemRepository를 직접사용 하면 더 간단하지 않은가?
◦
물론 위의 구조는 다른 DB를 사용할 때 편리하고, DI와 OCP원칙을 준수하고 있다
◦
하지만 그럼에도 더 단순화 시키고 싶다
다른 선택
NOTE
•
ItemService코드를 일부 고쳐서 직접 스프링 데이터 JPA를 사용하게 해보자.
◦
DI, OCP 원칙을 포기하는 대신에, 복잡한 어댑터를 제거하고 구조를 단순하게 가져갈 수 있다.
트레이드 오프
•
위의 2방식 비교
◦
DI, OCP를 지키기 위해 어댑터를 도입하면 더 많은 코드를 작성하게 된다.
◦
어댑터를 제거하고 구조를 단순하게 가져가면 DI, OCP는 깨진다
•
개발을 할 때 자원은 항상 무한한것이 아니다 그리고 어설픈 추상화는 오히려 독이된다.
•
추상화에도 비용이 드는만큼 추상화 비용을 넘어설 만큼의 효과가 나올 때 도입하는것이 실용적이다.
실용적인 구조 코드
NOTE
•
다음의 구조를 실제 코드로 작성해본다
ItemRepositoryV2
public interface ItemRepositoryV2 extends JpaRepository<Item, Long> {}
Java
복사
•
간단한 쿼리는 스프링 데이터 JPA로 처리
ItemQueryRepositoryV2
@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;
}
}
Java
복사
•
복잡한 쿼리는 Querydsl을 사용한다
ItemServiceV2
@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);
}
}
Java
복사
다양한 데이터 접근 기술 조합
NOTE
•
어떤 DB 기술을 선택하는 기준은 비즈니스 상황과, 현재 프로젝트 구성원의 역량에 따라 결정해야한다.
◦
JdbcTemplate나, Mybatic같은 기술들은 SQL을 직접 작성해야 하지만, 기술이 단순하기에 쉽게 적응할 수 있다
◦
JPA, 스프링 데이터 JPA, Querydsl 같은 기술들은 개발 생산성을 혁신할 수 있지만, 러닝커브가 높고, 복잡한 쿼리에 맞지않는다.
•
권장방식
◦
JPA, 스프링 데이터 JPA, Querydsl을 기본으로 사용
◦
복잡한 쿼리가 나오면, JdbcTemplate나, Mybatic 병행해서 사용.
[ 참고]
•
여러 DB를 사용하면 트랜잭션과 같은경우 각각의 트랜잭션 매니저가 다른데 어떻게 해야하는가?
◦
⇒ JpaTransactionManager는 DataSourceTrasactionManager가 제공하는 기능 대부분을 제공하므로, JPA, JdbcTemplate, MyBatix를 모두 하나의 트랜잭션으로 묶어서 사용할 수 있다!