DB를 사용할 경우 update 메서드가 필요할 수 있다.

지금은 조금 코드가 변경됐지만, 기존에 도메인 중심 설계를 위해 간단히 필드를 업데이트 하는 코드는 도메인 모델에 넣어두었다. 그런데, DB를 적용하자 필드는 적용되지 않는 문제가 발생했다. 이는 사실 당연한 문제로, 단순히 객체의 메서드를 실행할 뿐이기 때문이다.

기존 코드

public Rental rentBook(User user, Book book) {
    // remailrents가 없거나, 현재 누가 대출중인 경우 예외 발생함
    User rendtedUser = findUserByBookId(book.getBookId());

    if (user.equals(rendtedUser)) {
        throw new RentalException("이미 대출중입니다.");
    } else if (user.getRemainingRents() < 1) {
        throw new RentalException("더 이상 빌릴 수 없습니다.");
    } else if (book.isRented()) {
        throw new RentalException("이미 다른 유저가 대출중입니다.");
    }

    book.rentBook();
    user.rentBook();

    return bookRentalRepository.save(new Rental(book.getBookId(), user.getUserId()));
}

book의 is_rented 필드, user의 remaining_rents 필드를 변경해주지만, db에는 영향이 없다!

Service 계층에 update를 넣어주자

그런데, MemoryBookRepository까지 수정하는 것은 매우 비효율적이다. 애초에 메모리 리포지토리에서는 리포지토리 계층을 거칠 필요 조차 없기 때문이다. 따라서, DbXXXRepository를 만들었다.

public Book updateBook(Book book) {
    if (bookRepository instanceof DbBookRepository repository) {
        return repository.update(book);
    }

    return null;
}

repository가 DbXXXRepository라면, 다운캐스팅 이후에 update를 호출한다.

수정된 RentalService

따라서, update를 호출하는 RentalService에서는 이런 식으로 수정되었다.

public Rental rentBook(User user, Book book) {
    // remailrents가 없거나, 현재 누가 대출중인 경우 예외 발생함
    User rendtedUser = findUserByBookId(book.getBookId());

    if (user.equals(rendtedUser)) {
        throw new RentalException("이미 대출중입니다.");
    } else if (user.getRemainingRents() < 1) {
        throw new RentalException("더 이상 빌릴 수 없습니다.");
    } else if (book.isRented()) {
        throw new RentalException("이미 다른 유저가 대출중입니다.");
    }

    book.rentBook();
    user.rentBook();

    bookService.updateBook(book);
    userService.update(user);

    return bookRentalRepository.save(new Rental(book.getBookId(), user.getUserId()));
}

더불어, returnBook까지도 수정했다. Rental 역시 반납시 적용 안 되는 문제가 있었다.

    public void returnBook(User user, Book book) {
        User rendtedUser = findUserByBookId(book.getBookId());
        if (!user.equals(rendtedUser)) {
            log.debug("rendtedUser={}", rendtedUser);
            throw new RentalException("빌리지 않은 도서입니다.");
        }

        Rental rental = bookRentalRepository.findActiveRentalByBookId(book.getBookId())
                .orElseThrow(() -> new RentalException("이미 대출중인 도서입니다."));


        book.returnBook();
        user.returnBook();
        rental.returnBook();
        bookService.updateBook(book);
        userService.update(user);

        if (bookRentalRepository instanceof DbBookRentalRepository repository) {
            repository.update(rental);
        }
    }

    public User findUserByBookId(Long bookId) {
        return bookRentalRepository.findActiveRentalByBookId(bookId)
                .flatMap(rental -> userService.findById(rental.getUserId()))
                .orElse(null);
    }

댓글

개발자  김철준

백엔드 개발자 김철준의 블로그입니다.

주요 프로젝트