본문 바로가기
카테고리 없음

영속성 문제

by hbIncoding 2023. 4. 20.

1. 책 주문 하기 코드

	public ResponseEntity<BaseResponse> bookdemand(Long bookId, Integer quantity, HttpServletRequest request) {
		final String lockname = bookId + "lock";
		final RLock lock = redissonClient.getLock(lockname);

		HttpSession session = request.getSession(false);
		if (session == null) {
			return BaseResponse.toResponseEntity(ErrorCode.Forbidden);
		} else {

			try{
				if (!lock.tryLock(1,3, TimeUnit.SECONDS)){
					System.out.println("키 점거 실패");
					orderLogger.info("키 점거 실패");
					return BaseResponse.toResponseEntity(ErrorCode.CONFLICT_KEY);
				}

				Member member = (Member)request.getSession()
					.getAttribute(SessionConst.LOGIN_MEMBER);

				Book book = entityManager.find(Book.class, bookId);

				bookorder(book,quantity,member);


				orderLogger.info("bookId:{}, memberId:{}, state:{}, quantity:{}, totalPrice:{}",bookId,member.getId(),"order",quantity,book.getPrice()*quantity);

			}catch (Exception e){
				e.printStackTrace();
			}finally {
				if (lock != null && lock.isLocked()){
					lock.unlock();
				}
			}

			return BaseResponse.toResponseEntity(SuccessCode.ORDER_SUCCESS);
		}
	}

	@Transactional
	public void bookorder(Book book, Integer quantity, Member member){
		Long inven = book.getInventory()-quantity;

		if (inven<0){ // 재고가 0보다 작으면 잘 못된 주문
			throw new CustomException(ErrorCode.INVALIDATION_NOT_ENOUGH);
		}else if(inven ==0 ){ // 재고가 0이면 품절 -> modifiedAt 변경
			jumoonRepository.save(new Jumoon(member, book, quantity));
			book.inventoryChangeBook(inven);
			bookRepository.save(book);
		}else { // 품절되지 않으면 inventory만 바꿔줌
			jumoonRepository.save(new Jumoon(member, book, quantity));
			book.batchBook(inven);
			bookRepository.save(book);
		}
	}
  • 주문을 완료하고 book.batchbook / book.inventoryChangeBook으로 재고량을 바꿔주었다.
  • 하지만 다시 save를 해주어야 변경사항이 적용되었으며 그 전에는 적용되지 않았다.

2. 주문 취소 코드

public ResponseEntity<BaseResponse> cancelbook(Long jumoonId, HttpServletRequest request) {
		Member member = (Member)request.getSession()
			.getAttribute(SessionConst.LOGIN_MEMBER);

		Jumoon jumoon = jumoonRepository.findByIdAndMember(jumoonId, member).orElseThrow(
			()-> new CustomException(ErrorCode.Forbidden)
		);

		Long bookid = jumoon.getBook().getId();

		final String lockname = bookid + "lock";
		final RLock lock = redissonClient.getLock(lockname);

		try{
			if (!lock.tryLock(1,3, TimeUnit.SECONDS)){
				System.out.println("키 점거 실패");
				orderLogger.info("키 점거 실패");
				return BaseResponse.toResponseEntity(ErrorCode.CONFLICT_KEY);
			}

			Book book = entityManager.find(Book.class, bookid);

			Long inven = book.getInventory()+jumoon.getQuantity();
			book.inventoryChangeBook(inven);

			bookcancle(book,inven,jumoon);

			orderLogger.info("bookId:{}, memberId:{}, state:{}, quantity:{}, totalPrice:{}",book.getId(),member.getId(),"cancel",jumoon.getQuantity(),book.getPrice()*jumoon.getQuantity());

		}catch (Exception e){
			e.printStackTrace();
		}finally {
			if (lock != null && lock.isLocked()){
				lock.unlock();
			}
		}
		return BaseResponse.toResponseEntity(SuccessCode.ORDER_SUCCESS);
	}

	@Transactional
	public void bookcancle(Book book, Long inven, Jumoon jumoon){
		book.inventoryChangeBook(inven);
		jumoonRepository.delete(jumoon);

	}
  • 앞서 주문과 다르게 취소를 했을 때 book.inventoryChangeBook으로 재고량을 변경 시킨 뒤에 BookRepository를 이용해 save를 해주지 않아도 재고량이 다시 원상 복구 되었다.

3. 다른 해결 방법

	@Transactional
	public void bookorder(Book book, Integer quantity, Member member){
		Long inven = book.getInventory()-quantity;

		if (inven<0){ // 재고가 0보다 작으면 잘 못된 주문
			throw new CustomException(ErrorCode.INVALIDATION_NOT_ENOUGH);
		}else if(inven ==0 ){ // 재고가 0이면 품절 -> modifiedAt 변경
			book.inventoryChangeBook(inven);
			jumoonRepository.save(new Jumoon(member, book, quantity));
			// book.inventoryChangeBook(inven);
			// bookRepository.save(book);
		}else { // 품절되지 않으면 inventory만 바꿔줌
			book.batchBook(inven);
			jumoonRepository.save(new Jumoon(member, book, quantity));
			// book.batchBook(inven);
			// bookRepository.save(book);
		}
	}
  • 주문 저장이전에 재고량을 변경 시켜주면 해결이 된다.
  • save메서드를 사용하면 해당엔티티와 연관된 다른 엔티티들도 함께 영속성 컨텐스트에 등록