Spring Data ν¨λ°λ¦¬ κΈ°μ μ€ νλ
( Spring Data JDBC λ μ΄ μ€ νλ )
JPA κΈ°λ°μ λ°μ΄ν° μ‘μΈμ€ κΈ°μ μ μ’ λ μ½κ² μ¬μ©ν μ μκ² ν΄μ€
β λ°μ΄ν° μ‘μΈμ€ κ³μΈ΅μ ꡬνμ μμ΄ μ¬λ¬λΆμ κ°λ° μκ°μ λ¨μΆ
π‘ JPA vs Hibernate ORM vs Spring Data JPA
β β
- JPA
β Jakarta Persistence API(λλ Java Persistence API)
β μν°νλΌμ΄μ¦ Java μ ν리μΌμ΄μ μμ κ΄κ³ν λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬μ©νκΈ° μν΄ μ ν΄ λμ νμ€ μ€ν(Specification)
( βμ΄ κΈ°μ μ 무μμ΄κ³ , μ΄ κΈ°μ μ μ΄λ κ² μ΄λ κ² κ΅¬νν΄μ μ¬μ©νλ©΄ λΌβ λΌκ³ μ μ΄ λμ κΈ°μ λͺ μΈλΌκ³ μκ°νλ©΄ λ¨ )
β β - Hibernate ORM
β JPA μ€νμ ꡬνν ꡬν체
β μ€μ μ°λ¦¬κ° μ¬μ©ν μ μλ API
β β - Spring Data JPA
β JPA μ€νμ ꡬνν ꡬν체μ API(μΌλ°μ μΌλ‘ Hibernate ORM)λ₯Ό μ‘°κΈ λ μ½κ² μ¬μ©ν μ μλλ‘ ν΄μ£Όλ λͺ¨λ
β μ΄λ₯Ό μ¬μ©νμ¬ λ°μ΄ν° μ‘μΈμ€ κ³μΈ΅ ꡬν
β λ°μ΄ν° μ‘μΈμ€ κΈ°μ μ Spring Data JDBCμμ Spring Data JPAλ‘ λ°κΏ¨λ€κ³ ν΄μ μ€μ λ‘ μ½λ μμ²΄κ° λν λ³κ²½λ λΆλΆμ μμ
β
β μ ν리μΌμ΄μ μ΄ νΉμ κΈ°μ μ κ°νκ² κ²°ν©λμ§ μλλ‘ Springμ΄ μΆκ΅¬νλ PSA(μΌκ΄λ μλΉμ€ μΆμν)λ₯Ό ν΅ν΄,
κ°λ°μλ μΌκ΄λ μ½λ ꡬν λ°©μμ μ μ§νλλ‘ νκ³ , κΈ°μ μ λ³κ²½μ΄ νμν λ μ΅μνμ λ³κ²½λ§μ νλλ‘ μ§μνλ€
( β Repository λ΄μ find λ©μλ μμ μ¬μ© )
JPQLμ΄λΌλ κ°μ²΄ μ§ν₯ 쿼리λ₯Ό ν΅ν΄ λ°μ΄ν°λ² μ΄μ€ λ΄μ ν μ΄λΈμ μ‘°ν κ°λ₯
μν°ν° ν΄λμ€μ κ°μ²΄λ₯Ό λμμΌλ‘ κ°μ²΄λ₯Ό μ‘°ννλ λ°©λ²
( ν
μ΄λΈ λμμΌλ‘ μ‘°ν X )
JPQL λ¬Έλ²μ μ΄μ©νμ¬ κ°μ²΄ μ‘°ννλ©΄, JPAκ° λ΄λΆμ μΌλ‘ JPQLμ λΆμ ν μ μ ν SQLμ λ§λ€μ΄μ λ°μ΄ν°λ² μ΄μ€ μ‘°ν, κ·Έλ¦¬κ³ κ·Έ μ‘°νν κ²°κ³Όλ₯Ό μν°ν° κ°μ²΄λ‘ 맀ν ν λ°ν
Ex.
@Query(value = "SELECT c FROM Coffee c WHERE c.coffeeId = :coffeeId")
- coffeeIdμ ν΄λΉνλ μ»€νΌ μ 보λ₯Ό μ‘°ν ( SQL λ¬Έ μλ ! )
- Coffee - ν΄λμ€λͺ / coffeeId - Coffee ν΄λμ€μ νλλͺ / c - Coffee ν΄λμ€μ λ³μΉ
β - μ 쿼리문μ μλμ κ°μ΄λ λ³κ²½ κ°λ₯ ( SELECT cλ₯Ό μλ΅ν νν )
@Query(value = "FROM Coffee c WHERE c.coffeeId = :coffeeId")
[μ°Έκ³ ] https://en.wikibooks.org/wiki/Java_Persistence/JPQL
[μ°Έκ³ ] https://thorben-janssen.com/jpql/
Ex.
@Query(value = "SELECT * FROM COFFEE WHERE coffee_Id = :coffeeId")
- nativeQuery μ νΈλ¦¬λ·°νΈμ κ°μ βtrueβλ‘ μ€μ νλ©΄ value μ νΈλ¦¬λ·°νΈμ μμ±ν SQL μΏΌλ¦¬κ° μ μ©
π‘ Spring Data JDBCμ @Query vs Spring Data JPAμ @Query
- μ λν μ΄μ μ μ΄λ¦μ κ°μ§λ§ ν¨ν€μ§ μμ²΄κ° λ€λ¦
β ν¨ν€μ§ κ²½λ‘λ₯Ό νΌλνμ§ μλλ‘ μ£Όμν΄μΌ ν¨
β β - Spring Data JDBCμ @Query μ λν μ΄μ ν¨ν€μ§ κ²½λ‘
import org.springframework.data.jdbc.repository.query.Query
β β - Spring Data JPAμ @Query μ λν μ΄μ ν¨ν€μ§ κ²½λ‘
import org.springframework.data.jpa.repository.Query
βοΈ QueryDSL vs JOOQ
JPQLμ μμ±ν λ, 볡μ‘ν λ‘μ§μ κ²½μ° μΏΌλ¦¬ λ¬Έμμ΄μ΄ μλΉν κΈΈμ΄μ§
μ΄ κ²½μ°, 쿼리문 λ΄μ μ€ν / λ¬Έλ²μ μ€λ₯κ° μλ€λ©΄ λ°νμ μλ¬ λ°μ
β μ΄ λ¬Έμ λ₯Ό μ΄λμ λ ν΄μνλλ° κΈ°μ¬νλ νλ μμν¬λ€μ
[μ°Έκ³ ] https://tecoble.techcourse.co.kr/post/2021-08-08-basic-querydsl/
[μ°Έκ³ ] https://mycup.tistory.com/333
λ°μ΄ν°λ² μ΄μ€μ λ°μ΄ν°λ₯Ό μ μ₯ν λ, μμ±μΌμ / μμ μΌμ λ±μ μκ°μ λν μ€λ³΅ μ½λλ€μ μλμΌλ‘ κ°μ λ£μ΄μ£Όλ κΈ°λ₯
β Audit κΈ°λ₯μ μ΄μ©νλ©΄ μλμΌλ‘ μκ°μ 맀ννμ¬ λ°μ΄ν°λ² μ΄μ€μ ν
μ΄λΈμ λ£μ΄μ£Όκ² λ¨
@EnableJpaAuditing
μ λν
μ΄μ
μ μΆκ°
λ³΄ν΅ @SpringBootApplication
μ λν
μ΄μ
μ΄ μΆκ°λ ν΄λμ€μ λΆμ
JPA ConfigurationμΌλ‘ λ³λλ‘ κ΅¬μ±νλ κ²½μ°μ ν΄λΉ ν΄λμ€μ μΆκ°νλ κ²½μ° λ§μ
@EntityListeners (AuditingEntityListener.class)
[μ°Έκ³ ] https://wave1994.tistory.com/161
@MappedSuperclass
κ°μ²΄ μ μ₯μμ κ³΅ν΅ λ§€ν μ λ³΄κ° νμν λ μ¬μ©
JPA Entity ν΄λμ€λ€μ΄ μ΄ μ λν
μ΄μ
μ΄ λΆμ΄ 곡ν΅λ λ³μλ€μ μ 리ν΄λμ μΆμ ν΄λμ€λ₯Ό μμν κ²½μ°,
ν΄λΉ ν΄λμ€μ λ³μμΈ createdDate / modifiedDateλ₯Ό 컬λΌμΌλ‘ μΈμ
β μνΌ ν΄λμ€μ μλ νλμ ν¬ν¨λλ κ°λ€λ ν μ΄λΈμ λ°μνκ² λ€λ μλ―Έ
[μ°Έκ³ ] https://ict-nroo.tistory.com/129
@createdDate
β’ μν°ν° μμ±μΌμ μλ μΆκ°@LastModifiedDate
β’ μν°ν° μμ μΌμ μλ μΆκ°@createdBy
β’ μν°ν° μμ±μ μλ μΆκ°
β’ AuditorAware μΈν°νμ΄μ€λ₯Ό ꡬνν΄ μ£Όμ΄μΌ ν¨
κ°μ²΄ κ·Έλν νμμ ν΅ν΄ μ°κ΄ κ΄κ³λ₯Ό λ§Ίκ³ μλ κ°μ²΄λ₯Ό μ΄λ μμ μ μ‘°νν μ§λ₯Ό κ²°μ ν
λ μ λ΅
μ¦μ λ‘λ© ( FetchType.EAGER )
@ManyToOne
/ @OneToOne
μ§μ° λ‘λ© ( FetchType.LAZY )
@OnetoMany
/ @ManyToMany
βοΈ μ°κ΄κ΄κ³ 맀ν μ λν μ΄μ λ³ λν΄νΈ Fetch μ λ΅
@ManyToOne
/ @OneToOne
@OnetoMany
/ @ManyToMany
[μ°Έκ³ ] https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#fetching
[μ°Έκ³ ] https://rutgo-letsgo.tistory.com/199
μ΄μ μ€μ΅μ μΆκ°λ‘ ν΄μΌλλ λΆλΆ
1. μν°ν° ν΄λμ€λ₯Ό Spring Data JPAμ λ§κ² μμ
2. 리ν¬μ§ν 리(Repository) μΈν°νμ΄μ€ ꡬν
3. μλΉμ€ ν΄λμ€ κ΅¬ν
4. κΈ°ν κΈ°λ₯ μΆκ°λ‘ μΈν΄ μμ λ° μΆκ°λ μ½λ
μμ μ΄ νμν νλλ§ λ³΅μ¬ν΄μ μ λ°μ΄νΈ ν΄μ£Όλ κΈ°λ₯
Patch μ 보μ κ²½μ° μ½λκ° κ°κ²°ν΄μ§λ μ₯μ μ΄ μμ
Ex. μλ MemberService ν΄λμ€μ updateMember()
λ©μλλ₯Ό μ΄ν΄λ³΄λ©΄,
μ 보λ₯Ό κ°μ Έμμ μμ νλ λΆλΆμ΄ Optional.ofNullable λ‘ κΈΈκ² κ΅¬νλμ΄ μμ
β μ΄λ μμ ν΄μΌν μ 보λ€μ΄ λ§μ μλ‘ μ½λλ λ§μμ Έ μ μ§ λ³΄μ λ©΄μμ μ’μ§ μμ
λ°λΌμ, CustomBeanUtils< T >
ν΄λμ€λ₯Ό μ¬μ©νμ¬ μ΄λ₯Ό κ°λ¨νκ² λ§λ€ κ²μ
β¬οΈ μμ κ°μ΄ CustomBeanUtils< T >
ν΄λμ€λ₯Ό μ μνκ³
β¬οΈ μ΄λ₯Ό μ μ©ν MemberService ν΄λμ€μ μμ±μλ‘ μ£Όμ μ νλ€ !
β μ¬κΈ°μ μ£Όμν μ μ λ¨Όμ λ³μλ‘ μ§μ ν λ, CustomBeanUtils< T >
ν΄λμ€κ° μ λ€λ¦μΌλ‘ μμ±λμ΄ μκΈ° λλ¬Έμ < > μμ μ΄λ€ μν°ν°μ Service ν΄λμ€μ μ¬μ©μ ν μ§ μ μ΄μ€μΌν¨ !
β¬οΈ κ·Έλ¦¬κ³ μ΄λ₯Ό μ μ©ν MemberService ν΄λμ€ λ΄μ updateMember()
λ©μλμ
beanUtils ν΄λμ€ λ΄μ copyNonNullProperties λ©μλ μ¬μ©νμ¬ μμ
(μμ νκ³ μ νλ μ 보, λ£μ λ©μλλͺ
)λ₯Ό λ£κ³
beanUtils.copyNonNullProperties(member, findMember);
μ΄λ₯Ό λ³μμ λ£μ΄ κ·Έ λ³μλ₯Ό 리ν΄νλ©΄ 리ν©ν λ§ λ !
......................................................................................................................................................................................................
@Builder
ν¨ν΄μ΄ μ°μ
@AllArgsConstructor
μ΄ λ€μ μ°μ
( μμ±μμ λͺ¨λ νλλ₯Ό νλΌλ―Έν°λ‘ μ
λ ₯νλ λ°©λ² )
( @NoArgsConsturctor λ©΄ 맀νμ΄ μ μμ μΌλ‘ μλ¨ )
@Setter
κ° μ°μ μμμ λ§μ§λ§
μ€μ΅ κ³Όμ κ° μ λ§ μμ ν λΆλΆμ΄ λ§μμ μ΄λ €μ λλ° λ무 μ’μ νμ΄λμ λ§λμ λ§μ΄ λ°°μκ°λ μκ°μ΄μλ€ !!
μ§μ μμ ν΄λκ°λ©΄μ μ΄ν΄λ λΆλΆλ λ§μλ€.
λ¬Όλ‘ λ€ μ΄ν΄λμ§ μμμ§λ§ μ°¨μ°¨ 보λ€λ³΄λ©΄ κ²°κ΅μ λμ€μ λ€ μ΄ν΄λμ΄ μκ² μ§ !!
μλλ λΆλΆμ΄ μμ΄μ νμ΄κ° λλ λΉμΌ μ λ
μλ λ§λμ μμ νκ³ , κ·Έ λ€μ λ μλ λ¬΄λ € 8μκ° λ°λμ κ°μ΄ μμ νλ€ !
νμ£Όλ μλ νμΈμ μ κΉνμΈμ λλ€!! μλ‘νλ‘μ νΈ μ΄μλ―Έ κ²μνλ€λ³΄λ νμ£Όλ λΈλ‘κ·Έκ° λμμ μ λ³΄κ³ μ μ μ©νκ³ κ°λλ€ νμ£Όλ μ΅κ³ μμ 짱μ΄μμ
customBeanUtils, fetch μλ μλ€ μ΄ν΄κ° μ μλλλ° κΉλνκ² μ 리νμ λ΄μ© λ³΄κ³ μ΄μ μμΌ μ΄ν΄ν©λλ€ κ°μ¬ν©λλ€!
νλ‘μ νΈ νμλΆμ΄ 곡μ ν΄μ£Όμ λ§ν¬μΈλ° μ₯¬μ₯¬λ κΈμ΄μλ€μ!!
μμ λΈλ‘κ·Έ μ²μ¬ππ
μλ
νμΈμ νμ£Όλ. μ΄μ μ νμ΄ ν¨κ» νλ μ§ν¬μ£Όμ
λλ€ !!
μ λ νμλΆμκ² λ§ν¬ λ°μμ λ³΄κ² λλλ°, λΈλ‘κ·Έ κΈ μ λ¦¬κ° λ무 μ λμ΄ μμ΄μ 곡λΆνλλ° λ§μ΄ λμμ΄ λλ€μ !!! κΈ κ°μ¬ν μ λ³΄κ³ κ°λλ· ^>^ !!!!
1λΉ