packagejpabook.jpashop.domain.item;importjakarta.persistence.*;importjpabook.jpashop.domain.Category;importjpabook.jpashop.exception.NotEnoughStockException;importlombok.Getter;importlombok.Setter;importjava.util.ArrayList;importjava.util.List;@Entity@Inheritance(strategy=InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name="dtype")@Getter@SetterpublicclassItem{@Id@GeneratedValue@Column(name="item_id")privateLongid;privateStringname;privateintprice;privateintstockQuantity;@ManyToMany(mappedBy="items")privateList<Category>categories=newArrayList<>();//==비즈니스 로직==//// stock 증가publicvoidaddStock(intquantity){this.stockQuantity+=quantity;}// stock 감소publicvoidremoveStock(intquantity){intrestStock=this.stockQuantity-quantity;if(restStock<0){thrownewNotEnoughStockException("need more stock");}this.stockQuantity=restStock;}}
addStock( ): 파라미터로 넘어온 수만큼 재고를 늘린다. 이 매서드는 재고가 증가하거나 상품 주문을 취소해서 재고를 다시 늘려야 할 때 사용한다.
remove( ): 파라미터로 넘어온 수만큼 재고를 줄인다. 만약 재고가 부족하면 예외가 발생한다. 주로 상품을 주문할 때 사용한다.
상품 리포지토리 개발
packagejpabook.jpashop.repository;importjakarta.persistence.EntityManager;importjpabook.jpashop.domain.item.Item;importlombok.RequiredArgsConstructor;importorg.springframework.stereotype.Repository;importjava.util.List;@Repository@RequiredArgsConstructorpublicclassItemRepository{privatefinalEntityManagerem;// 상품 저장publicvoidsave(Itemitem){if(item.getId()==null){em.persist(item);}else{em.merge(item);}}// 아이템 하나 조회publicItemfindOne(Longid){returnem.find(Item.class,id);}// 전체 아이템 조회publicList<Item>findAll(){returnem.createQuery("select i from Item i",Item.class).getResultList();}}
상품 저장 (public void save( ) 세부 내용)
item은 JPA에 저장하기 전까지는(처음에는) id가 없다. 그래서 데이터를 저장할 때는 JPA가 제공하는 persist를 사용한다.
item이 없다 = 완전히 새로 생성한 객체이다.
만약 그게 아니라면 em.merge를 사용한다.
상품 서비스 개발
packagejpabook.jpashop.service;importjpabook.jpashop.domain.item.Item;importjpabook.jpashop.repository.ItemRepository;importorg.springframework.transaction.annotation.Transactional;importlombok.RequiredArgsConstructor;importorg.springframework.stereotype.Service;importjava.util.List;@Service@Transactional(readOnly=true)@RequiredArgsConstructorpublicclassItemService{privatefinalItemRepositoryitemRepository;// 상품 저장@TransactionalpublicvoidsaveItem(Itemitem){itemRepository.save(item);}// 상품 조회publicList<Item>findItems(){returnitemRepository.findAll();}publicItemfindOne(LongitemId){returnitemRepository.findOne(itemId);}}
상품 저장 (public void saveItem( )에 @Transactional 하는 이유
위의 @Transactional (readOnly = true) 때문에 다시 @Transactional 을 사용함으로써 오버라이드 함.