ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 데이터 접근 기술 - JPA
    스프링/스프링 기초DB 2023. 3. 26. 15:41

    데이터 접근을 할 때 가장 많이 사용되는 JPA라는 것을 공부할 것인데, 내용이 방대하기 때문에 블로그를 따로 만들어서 정리하고 여기서는 기본적인 내용만 살짝 공부할 것이다.

     

    db와 자바 객체간의 융합으로 쿼리를 일일이 짜지 않아도 JPA가 db에 쿼리를 넘겨주는 기술이다.

     

    @Data
    @Entity
    public class Item {
    
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
        // db에서 값을 넣어주는거니까 뒤와같이 IDENTITY
        private Long id;
    
        @Column(name = "item_name", length = 10)
        private String itemName;
        private Integer price;
        private Integer quantity;
    
        public Item() {
        }
    
        public Item(String itemName, Integer price, Integer quantity) {
            this.itemName = itemName;
            this.price = price;
            this.quantity = quantity;
        }
    }

    JPA를 사용하기 전에 기존에 있던 item 도매인을 다음과 같이 변경했다.

    @Entity : JPA가 사용하는 객체라는 뜻으로 이 애노테이션이 있어야 JPA가 인식할 수 있다.

    @Id : 테이블읠 PK와 해당 필드를 매핑함

    @GeneratedValue(strategy = GenerationType.IDENTITY : PK 생성 값을 데이터베이스에서 생성한다.

    (우리가 만들지 않고 db에서 하나씩 키워주는 방식처럼)

    @Column : 객체의 필드를 테이블의 컬럼과 매핑한다.

     

     

    JPA는 public이나 protected의 기본 생성자가 필수여서 무조건 넣어줘야한다.

     

     

    @Slf4j
    @Repository
    @Transactional
    public class JpaItemRepository implements ItemRepository {
    
        private final EntityManager em;
        // JPA를 사용하기 위해서 무조건 있어야하는 Manager
        // JPA의 모든 동작은 엔티티 매니저를 통해서 이루어짐
    
        public JpaItemRepository(EntityManager em) {
            this.em = em;
        }
    
    
        @Override
        public Item save(Item item) {
            em.persist(item);
            return item;
        }
    
        @Override
        public void update(Long itemId, ItemUpdateDto updateParam) {
            Item findItem = em.find(Item.class, itemId);
            findItem.setItemName(updateParam.getItemName());
            findItem.setPrice(updateParam.getPrice());
            findItem.setQuantity(updateParam.getQuantity());
            // 바꾸고 따로 저장을 하지 않아도 됨
            // 트랜잭션이 커밋되는 시점에 db에 저장됨
        }
    
        @Override
        public Optional<Item> findById(Long id) {
            Item item = em.find(Item.class, id);
            return Optional.ofNullable(item);
        }
    
    
    }

    JPA를 사용해서 repository를 만든 것이다. 코드가 이전에 비해 훨씬 간결하며 자바 코드와 거의 비슷하고, sql을 작성하거나 하는 그런 것들은 직접 해주지 않아도 된다. 예를 들면 save같은 동작은 persist 메서드만 해주면 되고 findById는 find 메서드만 해주면 된다. update의 기능은 find로 itemId를 찾아온 다음에 set을 통해 itemName과 Price, Quantity의 값을 바꿔도 된다. 따로 update를 해주는 메서드가 없는 이유는 JPA는 트랜잭션이 커밋되는 시점에 변경된 엔티티 객체가 있는지 확인하고 특정 엔티티 객체가 변경된 경우에는 UPDATE SQL을 실행한다.

    @Override
    public List<Item> findAll(ItemSearchCond cond) {
        String jpql = "select i from Item i";
        Integer maxPrice = cond.getMaxPrice();
        String itemName = cond.getItemName();
        if (StringUtils.hasText(itemName) || maxPrice != null) {
            jpql += " where";
        }
        boolean andFlag = false;
        if (StringUtils.hasText(itemName)) {
            jpql += " i.itemName like concat('%',:itemName,'%')";
            andFlag = true;
        }
        if (maxPrice != null) { if (andFlag) {
            jpql += " and";
        }
            jpql += " i.price <= :maxPrice";
        }
        log.info("jpql={}", jpql);
        TypedQuery<Item> query = em.createQuery(jpql, Item.class);
        if (StringUtils.hasText(itemName)) {
            query.setParameter("itemName", itemName);
        }
        if (maxPrice != null) {
            query.setParameter("maxPrice", maxPrice);
        }
        return query.getResultList();
    }

    하지만 findAll 메서드같은 동적쿼리를 짤 때는 불편하다. 전체 조회를 할 때 가격이나 상품명으로 조회를 할 수도 있기 때문에 위와 같은 상황은 동적쿼리를 짜야하는 상황이다. 그렇기 때문에 Querydsl이라는 기술을 활용해야한다. Querydsl을 사용하면 매우 깔끔한 코드로 변경되고 이 기술은 다음에 따로 포스팅하도록 하겠다.

     

    '스프링 > 스프링 기초DB' 카테고리의 다른 글

    데이터 접근 기술 - Querydsl  (0) 2023.03.28
    스프링 데이터 JPA  (0) 2023.03.26
    db 테스트에서의 트랜잭션  (0) 2023.03.25
    스프링 예외 추상화  (0) 2023.03.19
    체크 예외, 언체크(런타임) 예외  (0) 2023.03.19
Designed by Tistory.