반응형
Spring JPA
스프링 데이터 JPA는 JPA를 사용할때 지루하게 반복하는 코드를 자동화 해준다. 이미 라이브러리는 포함되어있다. MemberRepository를 스프링 데이터 JPA로 변경해보자.
public interface MemberRepository extends JpaRepository<Member, Long> {
//select m from Member m where m.name = ?
List<Member> findByName(String name);
}
public class MemberService {
private final MemberRepository memberRepository;
//회원 가입
@Transactional
public Long join(Member member) {
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
//EXCEPTION
List<Member> findMembers = memberRepository.findByName(member.getName());
if (!findMembers.isEmpty()) {
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
//회원 전체 조회
public List<Member> findMembers() {
return memberRepository.findAll();
}
//회원 한건 조회
public Member findOne(Long memberId) {
return memberRepository.findById(memberId).get();
}
@Transactional
public void update(Long id, String name) {
Member member = memberRepository.findById(id).get();
member.setName(name);
}
}
기존 MemberService의 findOne() 을 findById()로 변경해야 한다.
- 스프링 데이터 JPA는 JpaRepository라는 인터페이스를 제공하는데, 여기에 기본적인 CRUD 기능이 모두 제공된다.(일반적으로 상상할 수 있는 모든 기능이 다 포함되어 있다.)
- findByName처럼 일반화하기 어려운 기능도 메서드 이름으로 정확한 JPQL 쿼리를 실행한다.
- 개발자는 인터페이스만 만들면 된다. 구현체는 스프릥 데이터 JPA가 애플리케이션 실행 시점에 주입해준다.
** 스프링 데이터 JPA는 JPA를 사용해서 이런 기능을 제공할 뿐이다. 결국 JPA 자체를 잘 이해하는 것이 가장 중요하다.
QueryDSL
실무에서는 조건에 따라서 실행되는 쿼리가 달라지는 동적 쿼리를 많이 사용한다.
주문 내역 검색으로 돌아가보고, 이 예제를 Querydsl로 바꾸어보자.
QueryDSL은 자바 언어로 해결이 안되기 때문에 JPQL스러우면서도 자바 코드로 짜는 방법이다.
public List<Order> findAllByString(OrderSearch orderSearch) {
//language=JPAQL
String jpql = "select o From Order o join o.member m";
boolean isFirstCondition = true;
//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
if (isFirstCondition) {
jpql += " where";
isFirstCondition = false;
} else {
jpql += " and";
}
jpql += " o.status = :status";
}
//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
if (isFirstCondition) {
jpql += " where";
isFirstCondition = false;
} else {
jpql += " and";
}
jpql += " m.name like :name";
}
TypedQuery<Order> query = em.createQuery(jpql, Order.class)
.setMaxResults(1000); //최대 1000건
if (orderSearch.getOrderStatus() != null) {
query = query.setParameter("status", orderSearch.getOrderStatus());
}
if (StringUtils.hasText(orderSearch.getMemberName())) { query = query.setParameter("name", orderSearch.getMemberName());
}
return query.getResultList();
}
public List<Order> findAllByCriteria(OrderSearch orderSearch) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> o = cq.from(Order.class);
Join<Order, Member> m = o.join("member", JoinType.INNER); //회원과 조인
List<Predicate> criteria = new ArrayList<>();
//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
Predicate status = cb.equal(o.get("status"),
orderSearch.getOrderStatus());
criteria.add(status);
}
//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
Predicate name =
cb.like(m.<String>get("name"), "%" + orderSearch.getMemberName()
+ "%");
criteria.add(name);
}
cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 1000건
return query.getResultList();
}
반응형
'공부 > Spring Boot' 카테고리의 다른 글
API 개발 고급 - 실무 필수 최적화 (0) | 2025.02.19 |
---|---|
API 개발 고급 - 컬렉션 조회 최적화 (0) | 2025.02.19 |
API 개발 고급 - 지연 로딩과 조회 성능 최적화 (0) | 2025.02.03 |
API 개발 고급 - 준비 (0) | 2025.01.31 |
API 개발 기본 (0) | 2025.01.31 |