[Spring] 인터넷 강의 클론 5 - 비공개 / 공개 여부

춤인형의 개발일지·2025년 2월 21일

Spring실습

목록 보기
32/40

요구사항

  • 강의등록 시 기본적으로 비공개 상태
    • 비공개 상태
      • 조회: 목록 조회를 통해서는 조회되지 않음. 그러나 상세 조회를 통해서는 조회됨
      • 수강 신청 불가
  • 강의 공개
    • 특정 강의를 비공개공개로 전환 (전환 후에는 목록 조회를 통해서도 조회됨)

나의 생각
1. 등록할 때는 기본적으로 isPrivate = true 여야겠다.
2. @patchisPrivate = true->isPrivate = false로 변경
3. isPrivate = false는 setIsPrivate함수를 만들어서 사용하면 개발자 다른 분이 봐도 바뀐다고 인식할 것 같다.


비공개->공개

Entity

Lecture Entity에 private boolean isPrivate = true;을 추가해주고, 공개용 함수를 만든다.

public void setPublic(){
        this.isPrivate = false;
    }

Controller

@PatchMapping("/lectures/{lectureId}")
    public void updatePrivate(@PathVariable Long lectureId){
        lectureService.updatePrivate(lectureId);
    }

patch는 하나만, 한 부분만 수정하고 싶을 때 주로 사용한다.

Service

 @Transactional
    public void updatePrivate(Long lectureId) {
        Lecture lecture = lectureRepository.findById(lectureId)
                .orElseThrow(() -> new NoSuchElementException("찾는 강의가 없습니다."));

        lecture.setPublic();
        lectureRepository.save(lecture);
    }

@Transactional vs save()
현재 이 코드에서는 2가지가 같은 기능을 한다. 따라서 둘 중 하나만 있으면 된다. 두가지 중 어떤게 더 효과적인가?

그럼 어떻게 동작하는지 보자

  • @Transactional
  1. @Transactional이 붙어 있어 트랜잭션이 시작됨.
  2. lectureRepository.findById()를 통해 엔티티를 가져옴 → 영속성 컨텍스트(Persistence Context)에 저장됨.
  3. lecture.setPublic();을 호출하면 영속 상태 엔티티의 필드 값이 변경됨.
  4. 트랜잭션이 끝나는 시점에서 JPA의 변경 감지(dirty checking)가 동작해서 자동으로 UPDATE SQL 실행됨.
    : 즉, save() 없이도 변경 사항이 DB에 반영됨.
  • save()
  1. lectureRepository.findById()로 엔티티를 가져옴.
  2. lecture.setPublic();을 통해 필드 값을 변경함.
  3. lectureRepository.save(lecture);를 호출하면 JPA가 변경된 내용을 DB에 반영하기 위해 명시적인 UPDATE 쿼리를 실행함.

📌@Transactional : JPA의 변경 감지(dirty checking)를 활용하면 성능적으로 더 효율적
save()는 새로운 엔티티를 저장하거나, 비영속 상태의 엔티티를 업데이트할 때만 사용하는 것이 좋음.

❓그럼 언제 save()를 써야 할까?
객체가 영속성 컨텍스트에 없는 상태일 경우(비영속 상태)
Spring Data JPA의 @Transactional(readOnly = true)로 인해 변경 감지가 비활성화된 경우

따라서 나는 save말고, Transactional을 사용하겠다!

비공개인 강의는 조회, 수정할 때 보이지 않기

나는 QueryDsl로 사용하려고 한다.

 public List<Lecture> findAll(){
        return jpaQueryFactory
                .selectFrom(lecture)
                .join(lecture.teacher).fetchJoin()
                .where(
                        lecture.deleted.isFalse(),
                        lecture.isPrivate.isFalse())
                .orderBy(lecture.createTime.desc())
                .fetch();
    }

비공개가 false(=공개)인 부분만 조회하겠다!
요래 하면

@Test
    void 공개_강의목록조회() throws InterruptedException {
        LectureResponse lecture1 = createLecture(
                "자바 배우기",
                "자바, Spring을 통한 웹 개발 강의입니다.",
                50000,
                Category.Math,
                teacher.getId()
        );
        
        LectureResponse lecture2 = createLecture(
                "자바 응용하기",
                "자바, Spring을 통한 웹 개발 실습강의입니다.",
                50000,
                Category.Math,
                teacher.getId()
        );

        LectureResponse lecture3 = createLecture(
                "과학 배우기",
                "과학 강의입니다.",
                50000,
                Category.Science,
                teacher.getId()
        );
        updateLectureToPublic(lecture1.id());
        updateLectureToPublic(lecture2.id());

        List<LectureListResponse> list = RestAssured
                .given().log().all()
                .when()
                .get("/lectures")
                .then().log().all()
                .statusCode(200)
                .extract()
                .jsonPath()
                .getList(".", LectureListResponse.class);

        assertThat(list.size()).isEqualTo(2);
    }

이런 테스트를 통과할것이다!
테스트 내용은
강의 등록을 3개 해놓고, 비공개된 강의를 공개로 2개만 바꿔놨을 때 잘 돌아가냐를 테스트 해봤다. -> 테스트 통과!

0개의 댓글