BootCamp 50day

GyeongNamΒ·2024λ…„ 1μ›” 25일
0

BootCamp

λͺ©λ‘ 보기
44/49
post-thumbnail

πŸ“… 2024λ…„ 01μ›” 24일


50일차 : Spring (10)

μˆœν™˜μ°Έμ‘° (Circular Reference)

  • Author
@Entity
@Getter
@Builder
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
public class Author {
    /*
    authorλ₯Ό μ΄ˆκΈ°ν™” ν• λ•Œ post 객체가 ν•„μš”ν•  μ‹œμ— μ„œμ–Έ
    mappedBy의 μ—°κ΄€κ΄€κ³„μ˜ 주인을 λͺ…μ‹œν•˜κ³  , fkλ₯Ό κ΄€λ¦¬ν•˜λŠ” λ³€μˆ˜λͺ…을 λͺ…μ‹œ
     */
    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
    private List<Post> posts;
}
  • Post
@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Post {
    /*
    post 객체 μž…μž₯μ—μ„œλŠ” ν•œ μ‚¬λžŒμ΄ μ—¬λŸ¬ 글을 생성할 수 μžˆλ‹€.
    @JoinColumn(nullable = false, name = "autor_email", referencedColumnName = "email")
    author_idλŠ” DB의 컬럼λͺ…, 별닀λ₯Έ μ˜΅μ…˜μ—†μ„ μ‹œ author의 pk에 fk μ„€μ •
    */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "author_id")
    private Author author;
}
방법 예제 μ½”λ“œ
@JsonIgnore μ‚¬μš© ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ μ—”ν‹°ν‹° κ°„μ˜ μˆœν™˜ μ°Έμ‘°λ₯Ό λ¬΄μ‹œν•˜κ³  직렬화할 λ•Œ ν•΄λ‹Ή ν•„λ“œλ₯Ό μ œμ™Έν•  수 μžˆμŠ΅λ‹ˆλ‹€. 주둜 μ–‘λ°©ν–₯ κ΄€κ³„μ—μ„œ μ‚¬μš©λ©λ‹ˆλ‹€.
@JsonManagedReference, @JsonBackReference μ‚¬μš© `@JsonManagedReference`λŠ” 직렬화할 λ•Œ 참쑰된 객체λ₯Ό μ§λ ¬ν™”ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. `@JsonBackReference`λŠ” μ—­λ°©ν–₯ μ°Έμ‘°λ₯Ό μ§λ ¬ν™”ν•˜μ§€ μ•Šλ„λ‘ ν•©λ‹ˆλ‹€. μ–‘λ°©ν–₯ κ΄€κ³„μ—μ„œ 주둜 μ‚¬μš©λ©λ‹ˆλ‹€.
DTO μ‚¬μš© μ—”ν‹°ν‹° λŒ€μ‹  데이터 전솑 객체(DTO)λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•„μš”ν•œ μ •λ³΄λ§Œ 전달할 수 μžˆμŠ΅λ‹ˆλ‹€. DTOλ₯Ό 톡해 μˆœν™˜ μ°Έμ‘°λ₯Ό ν”Όν•˜κ³  ν•„μš”ν•œ λ°μ΄ν„°λ§Œ 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€.
Cascade, Fetch Type μ‘°μ • λΆ€λͺ¨ μ—”ν‹°ν‹°λ₯Ό μ‚­μ œν•  λ•Œ CascadeType.REMOVE λ˜λŠ” CascadeType.ALL이 μ„€μ •λœ μžμ‹ 엔티티도 ν•¨κ»˜ μ‚­μ œ, μ—°κ΄€ κ΄€κ³„μ˜ Fetch Type을 μ‘°μ •ν•˜μ—¬ 지연 λ‘œλ”©(Lazy Loading)을 μ‚¬μš©ν•˜λ©΄ μˆœν™˜ μ°Έμ‘°λ₯Ό ν”Όν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•„μš”ν•œ μ‹œμ μ—λ§Œ 데이터λ₯Ό λ‘œλ”©ν•©λ‹ˆλ‹€.
μˆœν™˜ μ°Έμ‘°κ°€ ν•„μš”ν•œ 경우 ν•΄κ²° μ „λž΅ 선택 일뢀 μƒν™©μ—μ„œλŠ” μˆœν™˜ μ°Έμ‘°κ°€ ν•„μš”ν•œ κ²½μš°λ„ μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•ŒλŠ” νŠΉμ •ν•œ ν•΄κ²° μ „λž΅μ„ μ„ νƒν•˜μ—¬ 문제λ₯Ό μ΅œμ†Œν™”ν•˜κ³  μ•ˆμ •μ μœΌλ‘œ λ™μž‘ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.

Spring Data JPA Query Method

  • AuthorRepository
@Repository
public interface AuthorRepository extends JpaRepository<Author,Long> {
    // findBy 컬럼λͺ…μ˜ κ·œμΉ™μœΌλ‘œ μžλ™μœΌλ‘œ where쑰건문을 μ‚¬μš©ν•œ λ©”μ„œλ“œ 생성
    Optional<Author> findByEmail(String email);
}
  • PostRepository
@Repository
public interface PostRepository extends JpaRepository<Post,Long> {
    List<Post> findByAuthor_Id(long author_id);
    List<Post> findAllByOrderByCreatedTimeDesc();
}
  • Query Method
ν‚€μ›Œλ“œ 예제 μ„€λͺ…
findBy findByFirstName(String firstName) `firstName` 속성을 기반으둜 λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findUserBy findUserByFirstNameAndLastName(...) μ—¬λŸ¬ 속성을 μ‘°ν•©ν•˜μ—¬ λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...And... findByFirstNameAndAge(String name, int age) μ—¬λŸ¬ 속성을 μ‘°ν•©ν•˜μ—¬ λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findAll findAll() λͺ¨λ“  λ ˆμ½”λ“œλ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€.
deleteBy deleteByLastName(String lastName) `lastName` 속성을 기반으둜 λ ˆμ½”λ“œλ₯Ό μ‚­μ œν•©λ‹ˆλ‹€.
removeBy removeByLastName(String lastName) `deleteBy`와 λ™μΌν•œ 역할을 ν•©λ‹ˆλ‹€.
countBy countByLastName(String lastName) `lastName` 속성을 기반으둜 λ ˆμ½”λ“œ 수λ₯Ό μ„ΈλŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
distinctBy findDistinctByLastName(String lastName) `lastName`을 기반으둜 쀑볡 제거된 λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findAllBy findAllByLastNameOrderByFirstNameAsc(...) `lastName`을 κΈ°μ€€μœΌλ‘œ `firstName`을 μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬ν•˜μ—¬ λͺ¨λ“  λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...Between findByAgeBetween(int min, int max) `age`κ°€ νŠΉμ • λ²”μœ„ 내에 μžˆλŠ” λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...IsNotNull findByLastNameIsNotNull() `lastName`이 null이 μ•„λ‹Œ λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...IsNull findByLastNameIsNull() `lastName`이 null인 λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...OrderBy...Desc findByLastNameOrderByAgeDesc(...) `lastName`을 κΈ°μ€€μœΌλ‘œ `age`λ₯Ό λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬ν•˜μ—¬ λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...GroupBy... findByLastNameGroupByAge(...) `lastName`을 κΈ°μ€€μœΌλ‘œ `age`λ₯Ό κ·Έλ£Ήν™”ν•œ λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...Having... findByLastNameHavingCountByAge(...) `lastName`을 κΈ°μ€€μœΌλ‘œ `age`의 κ°œμˆ˜κ°€ νŠΉμ • 쑰건을 λ§Œμ‘±ν•˜λŠ” λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...Like findByFirstNameLike(String pattern) `Like` μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•˜μ—¬ `firstName`이 νŠΉμ • νŒ¨ν„΄κ³Ό μΌμΉ˜ν•˜λŠ” λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...StartingWith findByLastNameStartingWith(String prefix) `lastName`이 νŠΉμ • μ ‘λ‘μ‚¬λ‘œ μ‹œμž‘ν•˜λŠ” λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...EndingWith findByLastNameEndingWith(String suffix) `lastName`이 νŠΉμ • μ ‘λ―Έμ‚¬λ‘œ λλ‚˜λŠ” λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.
findBy...Containing findByLastNameContaining(String sequence) `lastName`이 νŠΉμ • λ¬Έμžμ—΄μ„ ν¬ν•¨ν•˜λŠ” λ ˆμ½”λ“œλ₯Ό κ²€μƒ‰ν•©λ‹ˆλ‹€.

더티채킹(dirty checking)

public void update(long id, PostCreateDto postCreateDto ) throws EntityNotFoundException {
        Post post =  this.findById(id);
        post.postUpdate(postCreateDto.getTitle(), postCreateDto.getContents());
        postRepository.save(post);
//        postRepository.save(post); 없어도 μ €μž₯됌
};

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ μ—”ν‹°ν‹°μ˜ μƒνƒœ λ³€ν™”λ₯Ό κ°μ§€ν•˜κ³ , 이λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— μžλ™μœΌλ‘œ λ°˜μ˜ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜

1. νŠΈλžœμž­μ…˜ μ‹œμž‘:
μ—”ν‹°ν‹°μ˜ μƒνƒœ 변경은 νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€. νŠΈλžœμž­μ…˜μ΄ μ‹œμž‘λ˜λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ—”ν‹°ν‹°μ˜ μŠ€λƒ…μƒ·(초기 μƒνƒœ)을 μ €μž₯ν•©λ‹ˆλ‹€.
2. μ—”ν‹°ν‹° μƒνƒœ λ³€κ²½:
νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μ—”ν‹°ν‹°μ˜ 속성이 λ³€κ²½λ˜λ©΄, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” 이 λ³€κ²½ 사항을 μΆ”μ ν•©λ‹ˆλ‹€.
3. νŠΈλžœμž­μ…˜ 컀밋:
νŠΈλžœμž­μ…˜μ΄ 컀밋될 λ•Œ, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ—”ν‹°ν‹°μ˜ ν˜„μž¬ μƒνƒœμ™€ μŠ€λƒ…μƒ·μ„ λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ 뢀뢄을 κ°μ§€ν•©λ‹ˆλ‹€.
4. λ°μ΄ν„°λ² μ΄μŠ€ μ—…λ°μ΄νŠΈ:
λ³€κ²½λœ 뢀뢄이 κ°μ§€λ˜λ©΄, JPAλŠ” ν•΄λ‹Ή 엔티티에 λŒ€ν•œ UPDATE 쿼리λ₯Ό μƒμ„±ν•˜μ—¬ λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•©λ‹ˆλ‹€.

Spring μ‹€μŠ΅ github 링크

profile
503 Service Unavailable Error

0개의 λŒ“κΈ€