실전 활용1 JPA _개발(상품,)

링딩·2021년 6월 27일
0

Spring

목록 보기
3/5

상품 도메인 개발

상품 엔티티 개발

(구현 기능): ¹상품 등록 ²상품 목록 조회 ³상품 수정

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) //한테이블에 떄려박는 느낌으로.
@DiscriminatorColumn(name = "dtype") //SINGLE_TABLE 아래의 타입들을 찾고자
@Getter @Setter
//@Setter -> 핵심 비즈니스의 값을 변경할때 굳이 필요 없이 필요한 곳에서 메서드를 만들어야 함

//구현체를 가지기 위해- 추상클래스
public abstract class Item {

    @Id
    @GeneratedValue
    @Column(name = "item_id") //pk 설정
    private Long id;
    
    .
    .
    .
    private int stockQuantity; //재고수량
    
    //--비즈니스 로직--/
    //왜 이곳에?
    //객체지향적으로 이 객체를 가지고 있는 쪽에서 메서드를 만드는 것이 가장 좋기 때문
    /*
    * 재고수량 증가 (stock 증가)
    * */
    public void addStock(int quantity){
        this.stockQuantity += quantity;
    }

    /*
    *  stock 재고수량 감소
    * */
    public  void removeStock(int quantity){
        int restStock = this.stockQuantity - quantity;
        if(restStock <0 ){
            throw new NotEnoughStockException("need more stock");
        }
        this.stockQuantity=restStock;
    }


}

1) 비즈니스 로직 생성 _(재고수량 측정)

[이 강아지의 코딩공부, Gemini Kim블로그에서 setter를 언제 쓰면 좋을지 참고하였습니다!]
@Setter을 굳이 지양하고 비즈니스 로직을 해당 클레스에서 만들어야 할까?

📣) @Setter의 지양
jpa는 트랜젝션 안에서 Entity의 변경사항을 감지해 UPDATE SQL을 생성한다.
=> @Setter로 인해 UPDATE 기능이 수행되고 있었다.
=> 예측하지 못한 곳에서 update가 일어나면 일일히 Setter을 확인하는 불편이 생길 수 있다.

이러한 여러가지 관점으로 인해 이렇게 setter을 대신해 메서드를 이용하여, 관련된 해당 클래스에 비즈니스 로직을 생성해주는 것이 좋다. 굳이 다른 클래스에서 setter를 이용해 값을 하나하나 불러와 변경할 필요가 없게 된다.


상품 리포지토리

@Repository
@RequiredArgsConstructor
public class ItemRepository {

    //스프링 데이터 jpa땜에
    private  final EntityManager em;

    //*상품저장* item은 맨처음엔 id가 없음
    public void save(Item item){
        //맨 처음에는 id값이 없다 == 새로 생성한 객체
        if(item.getId() == null){

            em.persist(item); //신규로 등록하기

        }else{//이미 등록되어 있는 것->DB에서 가져와서  저장된 엔티티를 수정한다 생각하자.
            //자세한 것은 웹 뒤에서
            em.merge(item);
        }
    }

    public Item findOne(Long id){
        return em.find(Item.class, id); //단건 조회니까 find() 쓰자
    }

    public List<Item> findAll(){
        return em.createQuery("select i from Item i", Item.class)
                .getResultList();
    }

}

1)persist(), merge()

영속성 컨텍스트와 JPA에 관하여 이 Namjun Kim 블로그를 참조하였습니다.

  • 맨처음 id는 값이 없으므로 save() 메서드에서는 id값을 확인 후 em.persist()로 최초 생성된 엔티티를 영속화 한다.
    => 즉 신규라고 생각, '신규등록'한다.
  • 그러나 id 값이 null이 아닌 경우 em.merge()를 써준다. 이를 생각해보면 객체가 이미 등록되어 있다.
    -> 그러므로 저장되어 있는 엔티티를 가져와 수정한다 생각하자...

상품 서비스

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

    private  final ItemRepository itemRepository;

    @Transactional //위에 (readOnly)때문에 읽기전용이면 저장이 안됨.->쓰기로 바꿔줌
    public void saveItem(Item item){
        itemRepository.save(item);
    }

    public List<Item> findItems(){
        return itemRepository.findAll();
    }

    public Item findOne(Long itemId){
        return itemRepository.findOne(itemId);
    }


}

상품 서비스는 단순히 상품 리포지토리에 위임한게 다이다.

@Transactional(readOnly=true)로 되어 있기 때문에 저장이 필요한 saveItem()메서드만 따로 '읽기전용'에서 '쓰기전용'으로 바꿔주었다.

테스트는 회원 테스트와 비슷하므로 건너뛴다.



profile
초짜 백엔드 개린이

0개의 댓글