스프링부트와 JPA 활용1

권영태·2023년 5월 16일
0

스프링

목록 보기
11/18

스프링부트와 JPA를 활용해 웹 애플리케이션을 개발한다.
다음 코드 및 진행 방법은 인프런 김영한 강사님의 유로 강의 내용을 발췌한 내용이다.
강의 : <실전! 스프링 부트와 JPA 활용 1 - 웹 애플리케이션 개발>

출처 : https://inf.run/zzKt

강의를 들으며 추가로 궁금한 내용과 제대로 이해되지 않은 부분을 정리한다.

❓이건 뭘까?!

  • 동적 쿼리 : 상황(동적으로 들어오는 파라미터 값)에 따라 달라지는 쿼리문
  • setFirstResult(int maxResult) : 값 조회 시작 위치
  • setMAXResults(int startPosition) : 조회할 데이터 수
  • Criteria : JPQL 작성을 도와주는 Builder Class
  • Predicate : Predicate에서 T에 대한 조건에 대해 True/False를 반환하는 함수형 인터페이스 * Java 문법
  • @RequestMapping("/") : 특정 URL로 요청 시 해당 Controller에서 어떤 방식으로 처리할지 정의하는 어노테이션
  • @valid : 객체 제약조건을 검증하는 기본 자바 기술(어노테이션)
    • @validated는 Spring에서 제공
  • BindingResult : 검증 오류를 보관하는 객체로 보관 방법은 3가지
    • 1) 객체 타입 등의 오류로 바인딩 실패
      2) 개발자가 직접 넣어주는 경우
      3) valid 또는 validated의 검증을 실시하는 valitor를 사용하는 경우
  • 바인딩 : 사용자 입력 값을 객체 필드에 매핑하는 과정
  • 준영속 상태 : 영속성 상태였던 엔티티가 영속성 컨텍스트가 사라진 것
    비영속 상태와 다른 점은 한번 영속상태가 된 적이 있는가 없는가 차이
  • @RequestParam : Controller에서 파라미터 값을 넘겨 받을 때 사용하는 어노테이션
    • @PathVariable과 동일하게 데이터를 받아오는데 사용한다.
      하지만 @PathVariable는 값을 하나만 받아올 수 있는 반면 @RequestParam은 쿼리스트링을 이용해 여러 데이터를 받아올 수 있다.
  • @Slf4j : Logger Class와 동일한 기능 어노테이션

💡아하!

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderService {

   private final OrderRepository orderRepository;
   private final MemberRepository memberRepository;
   private final ItemRepository itemRepository;

   /**
    * 주문
    */
   @Transactional
   public Long order(Long memberId, Long itemId, int count) {

       //엔티티 조회
       Member member = memberRepository.findOne(memberId);
       Item item = itemRepository.findOne(itemId);

       //배송정보 생성
       Delivery delivery = new Delivery();
       delivery.setAddress(member.getAddress());

       //주문상품 생성
       OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);

       //주문 생성
       Order order = Order.createOrder(member, delivery, orderItem);

       //주문 저장
       orderRepository.save(order);    // Cascade 옵션 때문에
       return order.getId();
   }

   /**
    * 주문 취소
    */
   @Transactional
   public void cancelOrder(Long orderId) {
       //주문 엔티티 조회
       Order order = orderRepository.findOne(orderId);
       //주문 취소
       order.cancel();
   }

   //검색
   public List<Order> findOrders(OrderSearch orderSearch) {
        return orderRepository.findAllByString(orderSearch);
   }
  • cascade의 영속성 전이 덕분에 orderService에서 order만 save해도
    OrderRepository안 persist.save()가 로직이 있어 전부 save됨
    • 다른것들이 관여하지 않고 명확하게 한개에서 관리할때만 영속성을 하는게 좋음! (Order → delivery / Order→ OrderItem)
  • JPA의 큰 장점 중 하나로 Entity안에서 데이터를 변경하면 JAP가 알아서 바뀐 변경 포인트를 찾아서(Dirty Checking) 변경 내역 감지가 된 데이터의 쿼리를 DB에 날린다.
public class MemberForm {

    @NotEmpty(message = "회원 이름은 필수 입니다.")
    private String name;

    private String city;
    private String street;
    private String zipcode;
}
  • @notEmpty : Not null, 만약 null이면 message 생성
  • Controller에서 Service로 Entity 객체를 넘기는 것보다 DTO(MemberForm)로 넘기는게 좋음
    • Entity 객체로 못 넘기는건 아님!
    • 다만 API일 땐 Entity 객체를 못 넘김!
@Repository
@RequiredArgsConstructor
public class ItemRepository {

    private final EntityManager em;

    public void save(Item item) {
        if (item.getId() == null) { // item의 id값이 null은 처음 생성 된 객체라는 의미
            em.persist(item);  // EntityManagaer을 통해 영속성 부여
        } else {
            em.merge(item);
        }
    }

    public Item findOne(Long id) {
        return em.find(Item.class, id);
    }

    public List<Item> findAll() {
        return em.createQuery("select i from Item i", Item.class)   // 모든 값은 SQL문(쿼리)를 써야됨!!
                .getResultList();
    }
}
  • merge(item)은 업데이트 느낌(진짜 업데이트는 아님!)
    • merge에 담긴(ex. Item merge = em.merge(item)) 값이 영속성으로 바뀌는거지, em.merge(item)이 영속성으로 바뀌는게 아님!
profile
GitHub : https://github.com/dudxo

0개의 댓글