JPA Programming Basic
JPA Programming Basic
μνλμ μλ° ORM νμ€ JPA νλ‘κ·Έλλ° - κΈ°λ³ΈνΈ κ°μλ₯Ό μμ½ν λ΄μ©μ λλ€.
Intro
JPA
Java Persistence API
μλ° μ§μμ ORM κΈ°μ νμ€ (μΈν°νμ΄μ€μ λͺ¨μ)
ꡬν체λ‘λ Hibernate, EclipseLink, DataNucleus..
Applicationκ³Ό JDBC μ¬μ΄μμ λμ
ROM
Object-Relational Mapping
Objectλ Objectλλ‘, RDBMSλ RDBMSλλ‘ μ€κ³
ORM νλ μμν¬κ° μ€κ°μμ λ§€ν
EntityManagerFactory
persistence.xml μ€μ μ 보 νμΈ ν persistence-unit name μ λ§λ EntityManagerFactory μμ±
Web Server κ° μμ±λλ μμ μ νλλ§ μμ±ν΄μ μ ν리μΌμ΄μ μ 체μμ 곡μ
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager
μμ² κ±΄λ§λ€ μμ±
μ°λ λκ° κ³΅μ νλ©΄ μ λκ³ , μ¬μ© ν μ’ λ£
EntityTransaction
JPAμ λͺ¨λ λ°μ΄ν° λ³κ²½μ νΈλμ μ μμμ μ€ν
μμμ± κ΄λ¦¬
μμμ± μ»¨ν
μ€νΈ
PersistenceContext (μν°ν°λ₯Ό μꡬ μ μ₯νλ νκ²½)
EntityManager λ₯Ό ν΅ν΄ PersistenceContext μ μ κ·Ό
EntityManager, PersistenceContext λ
1:1,N:1κ΄κ³ μ‘΄μ¬
μν°ν° μλͺ μ£ΌκΈ°
λΉμμ(new / transient)μμμ± μ»¨ν μ€νΈμ μ ν κ΄κ³κ° μλ μλ‘μ΄ μν
μμ(managed)μμμ± μ»¨ν μ€νΈμ κ΄λ¦¬λλ μν
μ€μμ(detached)μμμ± μ»¨ν μ€νΈμ μ μ₯λμλ€κ° λΆλ¦¬λ μν
μμ (removed)μμ λ μν
.
μμμ± μ»¨ν μ€νΈμ μ΄μ
1μ°¨ μΊμμμμ μ‘°νμ¬μ©μμ νλμ μμ²-μλ΅(νλμ νΈλμ μ ) λ΄μμλ§ ν¨κ³Όκ° μμΌλ―λ‘ μ±λ₯ μ΄μ μ κΈ°λνμ§λ μμ.
μν°ν° μ‘°ν μ λ¨Όμ 1μ°¨ μΊμμμ μ‘°ν ν, μμ κ²½μ° DBμμ μ‘°ν
μμ μν°ν°μ
λμΌμ±(identity) 보μ₯1μ°¨ μΊμλ‘ λ°λ³΅ κ°λ₯ν μ½κΈ°(REPEATABLE READ) λ±κΈμ νΈλμμ 격리 μμ€μ λ°μ΄ν°λ² μ΄μ€κ° μλ μ ν리μΌμ΄μ μ°¨μμμ μ 곡
νΈλμμ μ μ§μνλ
μ°κΈ° μ§μ°(transactional write-behind)Queryλ₯Ό μμ λλ€κ° transaction.commit() μ νλ μκ° λ°μ΄ν°λ² μ΄μ€μ Query μ μ‘
λ³κ²½ κ°μ§(Dirty Checking)transaction.commit() μμ μ μν°ν°μ μ€λ μ·(μ²μ μ½μ΄ μ¨ μν°ν° μν) λΉκ΅ ν λ³κ²½μ΄ κ°μ§λλ©΄ Update Query λ₯Ό μ°κΈ° μ§μ° SQL μ μ₯μμ μ μ₯
μ΄ν DBμ Query μ μ‘ λ° Commit
μ§μ° λ‘λ©(Lazy Loading)
.
Flush
μμμ± μ»¨ν μ€νΈμ λ³κ²½λ΄μ©μ λ°μ΄ν°λ² μ΄μ€μ λ°μνλ μν
λ°μ μμ
λ³κ²½ κ°μ§
μ°κΈ° μ§μ° SQL μ μ₯μμ 쿼리λ₯Ό λ°μ΄ν°λ² μ΄μ€μ μ μ‘ (CUD Query)
νΈμΆ λ°©λ²
μ§μ νΈμΆ : em.flush()
μλ νΈμΆ : νΈλμμ 컀λ°, JPQL 쿼리 μ€ν
μν°ν° λ§€ν
κ°μ²΄μ ν μ΄λΈ
κ°μ²΄μ ν μ΄λΈ λ§€ν
@Entity: JPAκ° κ΄λ¦¬νλ ν΄λμ€ (κΈ°λ³Έ μμ±μ νμ)@Table: μν°ν°μ λ§€νν ν μ΄λΈ μ§μ
νλμ μ»¬λΌ λ§€ν
@Column
κΈ°λ³Έ ν€ λ§€ν
@Id
μ°κ΄κ΄κ³ λ§€ν
@ManyToOne@JoinColumn
.
λ°μ΄ν°λ² μ΄μ€ μ€ν€λ§ μλ μμ±
@Entityκ° μλ ν΄λμ€ DDLμ μ ν리μΌμ΄μ μ€ν μμ μ μλ μμ± (κ°λ° νκ²½μμλ§ μ¬μ©)
create: κΈ°μ‘΄ν μ΄λΈ μμ ν λ€μ μμ± (DROP + CREATE)create-drop: createμ κ°μΌλ μ’ λ£μμ μ ν μ΄λΈ DROPupdate: λ³κ²½λΆλ§ λ°μ(μ΄μDBμλ μ¬μ©νλ©΄ μλ¨)validateμν°ν°μ ν μ΄λΈμ΄ μ μ λ§€νλμλμ§λ§ νμΈnone: μ¬μ©νμ§ μμ
μ£Όμ
μ΄μ μ₯λΉμλ μ λ create, create-drop, update μ¬μ©νλ©΄ μλ¨.
κ°λ° μ΄κΈ° λ¨κ³λ create λλ update
ν μ€νΈ μλ²λ update λλ validate
μ€ν μ΄μ§κ³Ό μ΄μ μλ²λ validate λλ none
.
νλμ 컬λΌ
.
κΈ°λ³Έ ν€
@Id: μ§μ ν λΉν κ²½μ°@GeneratedValue: μλ μμ±ν κ²½μ°AUTO : λ°©μΈμ λ°λΌ μλ μ§μ (default)
IDENTITY : λ°μ΄ν°λ² μ΄μ€μ μμ (MYSQL)
μ£Όλ‘ MySQL, PostgreSQL, SQL Server, DB2 μμ μ¬μ©
μ°Έκ³ ) DB INSERT Query μ€ν νμ ID κ°μ μ μ μμΌλ―λ‘, em.persist() μμ μ μ¦μ INSERT Query μ€ν λ° DB μλ³μ μ‘°ν
SEQUENCE : λ°μ΄ν°λ² μ΄μ€ μνμ€ μ€λΈμ νΈ μ¬μ© (ORACLE, @SequenceGenerator)
μ£Όλ‘ μ€λΌν΄, PostgreSQL, DB2, H2 μμ μ¬μ©
TABLE : ν€ μμ±μ© ν μ΄λΈ μ¬μ©, (λͺ¨λ DB, @TableGenerator)
Long Type + λμ²΄ν€ + ν€ μμ±μ λ΅ μ¬μ© κΆμ₯
AUTO & IDENTITY
SEQUENCE
allocationSize
μνμ€λ₯Ό ν λ² νΈμΆν λ μ¦κ°νλ μ (μ±λ₯ μ΅μ νμ μ¬μ©, default. 50)
μΉ μλ²λ₯Ό λ΄λ¦¬λ μμ μ λ©λͺ¨λ¦¬μ μ μ₯λμ΄μλ μνμ€λ€μ΄ λ λΌκ°μ ꡬλ©μ΄ μκΈ°λ―λ‘, 50~100μ΄ μ μ
DB μνμ€ κ°μ΄ νλμ© μ¦κ°νλλ‘ μ€μ λμ΄ μλ€λ©΄, μ΄ κ°μ λ°λμ 1λ‘ μ€μ
ex) μ΄κΈ° 1 ~ 51 κΉμ§ μ‘°ν, μ΄ν μνμ€λ DBμμ μ‘°ννμ§ μκ³ λ©λͺ¨λ¦¬μμμ μ‘°ν
λ©λͺ¨λ¦¬μμ μνμ€ 51μ λ§λλ μκ° λ€μ DBμμ μ‘°ν(next call)
미리 μνμ€ κ°μ μ¬λ €λλ―λ‘ λμμ± λ¬Έμ κ° λμ§ μμ
μ΄ λΆλΆμ Table μ λ΅λ μ μ¬
μ°κ΄κ΄κ³ λ§€ν
JPAλ κ°μ²΄μ μ°Έμ‘°μ ν μ΄λΈμ μΈλ ν€λ₯Ό λ§€ν
λ°©ν₯(Direction)
λ¨λ°©ν₯
μλ°©ν₯
κ°μ²΄μ μλ°©ν₯ κ΄κ³λ μ¬μ€ μλ‘ λ€λ₯Έ λ¨λ±‘ν₯ κ΄κ³ 2κ°λΌλ μ¬μ€.
κ°μ²΄λ₯Ό μλ°©ν₯μΌλ‘ μ°Έμ‘°νλ €λ©΄ λ¨λ°©ν₯ μ°κ΄κ΄κ³λ₯Ό 2κ° λ§λ€μ΄μΌ ν¨
ν μ΄λΈμ μΈλ ν€ νλλ‘ λ ν μ΄λΈμ μ°κ΄κ΄κ³λ₯Ό κ΄λ¦¬
μ°κ΄κ΄κ³μ μ£ΌμΈ(Owner)
μΈλν€λ₯Ό κ΄λ¦¬νλ μ°Έμ‘°
μλ°©ν₯ λ§€ν κ·μΉ
κ΄κ³λ₯Ό κ°λ λ κ°μ²΄ μ€ νλμ κ°μ²΄λ₯Ό μ°κ΄κ΄κ³μ μ£ΌμΈμΌλ‘ μ§μ
μ°κ΄κ΄κ³μ μ£ΌμΈλ§μ΄ μΈλ ν€λ₯Ό κ΄λ¦¬(λ±λ‘, μμ )νκ³ , μ£ΌμΈμ΄ μλ μͺ½μ μ‘°νλ§ κ°λ₯
μ£ΌμΈμ΄ μλ κ°μ²΄μ νλμ mappedBy μμ±μΌλ‘ μ£ΌμΈ νλλ₯Ό μ§μ
μ°κ΄κ΄κ³μ μ£ΌμΈμ λ€(
N:1)μ ν΄λΉνλ κ°μ²΄μͺ½μ΄ κ°λλ‘(μΈλν€λ₯Ό κ°λ ν μ΄λΈ κΈ°μ€)μ°κ΄κ΄κ³μ μ£ΌμΈμ κ° μ€μ νκΈ°
μ°κ΄κ΄κ³ νΈμ λ©μλλ₯Ό μμ±νλ κ²μ΄ νΈλ¦¬
μλ°©ν₯ λ§€νμμ 무ν 루νλ‘ μΈν StackOverflow μ‘°μ¬νκΈ°
toString(), lombok, JSON μμ± λΌμ΄λΈλ¬λ¦¬(=> Controller DTO λ°νμΌλ‘ ν΄κ²°)
λ¨λ°©ν₯ λ§€νλ§μΌλ‘λ μ°κ΄κ΄κ³ λ§€νμ μλ£λ μν.
μΆν μλ°©ν₯ νμμ΄ νμν κ²½μ°μ μΆκ°νκΈ°!(ν μ΄λΈμ μν₯ X)
λ€μ€μ±(Multiplicity)
λ€λμΌ(N:1) - @ManyToOne
ν μ΄λΈ μΈλν€ κΈ°μ€μΌλ‘ μ°κ΄λ μ°Έμ‘°λ₯Ό μ€μ (Nμ΄ μ°κ΄κ΄κ³μ μ£ΌμΈ)
μλ°©ν₯ μ°κ²°μ ν κ²½μ°, λ°λ κ°μ²΄μλ OneToMany λ°©ν₯ μ€μ μΆκ°(μ‘°νλ§ κ°λ₯)

μΌλλ€(1:N) - @OneToMany
μΌλλ€ λ¨λ°©ν₯
μμ λ°λ μΌμ΄μ€λ‘ μΌ(1)μ΄ μ°κ΄κ΄κ³μ μ£ΌμΈμ΄ λ κ²½μ°, A(1) ν μ΄λΈ μ λ°μ΄νΈλ₯Ό μλνμ§λ§ B(N) ν μ΄λΈλ ν¨κ» μ λ°μ΄νΈλ₯Ό ν΄μΌνλ μν©μΌλ‘ μ¬λ¬ μ΄μ λ°μ μμκ° μκΉ
μν°ν°κ° κ΄λ¦¬νλ μΈλν€κ° λ€λ₯Έ ν μ΄λΈμ μμΌλ―λ‘ μ°κ΄κ΄κ³ κ΄λ¦¬λ₯Ό μν΄ μΆκ° μ λ°μ΄νΈ 쿼리 λ°μ
μΌλλ€ μλ°©ν₯ μ°κ²°μ 곡μμ μΌλ‘ μ‘΄μ¬νμ§ μλ λ§€ν
μΌλλ€ λ¨λ±‘ν₯ λ§€νλ³΄λ€ λ€λμΌ μλ°©ν₯ λ§€νμ μ¬μ©νμ
μΌλμΌ(1:1) - @OneToOne
ex) νμκ³Ό κ°μΈ λ½μ»€μ κ΄κ³
μΈλν€μ DB μ λν¬(UNI) μ μ½μ‘°κ±΄ νμ
μ€μ μ λ€λμΌ λ§€νκ³Ό μ μ¬
μ£Ό/λμ ν μ΄λΈ μ€μ μΈλν€ μ ν κ°λ₯
μ£Ό ν μ΄λΈ μ ν
JPA λ§€νμ΄ νΈλ¦¬νμ¬ κ°μ²΄μ§ν₯ κ°λ°μ μ νΈ
μ₯μ . μ£Ό ν μ΄λΈλ§ μ‘°νν΄μ λμ ν μ΄λΈ λ°μ΄ν° νμΈ κ°λ₯
λ¨μ . κ°μ΄ μμΌλ©΄ μΈλν€μ null νμ©

λμ ν μ΄λΈ μ ν
μ ν΅ DB κ°λ°μ μ νΈ
μ₯μ . μ£Ό/λμ ν μ΄λΈμ 1:1 κ΄κ³μμ 1:N κ΄κ³λ‘ λ³κ²½ μ ν μ΄λΈ ꡬ쑰 μ μ§ κ°λ₯
λ¨μ . νλ‘μ κΈ°λ₯μ νκ³λ‘ μ§μ° λ‘λ©μΌλ‘ μ€μ ν΄λ νμ μ¦μ λ‘λ©

λ¨λ°©ν₯
μλ°©ν₯
λ€λλ€(N:M) - @ManyToMany
RDBλ μ κ·νλ ν μ΄λΈ 2κ°λ‘ λ€λλ€ κ΄κ³λ₯Ό ννν μ μμΌλ―λ‘ μ€κ° ν μ΄λΈμ΄ νμ
κ°μ²΄λ @ManyToMany, @JoinTableλ‘ λ€λλ€ κ΄κ³λ₯Ό ννν μ μμ§λ§, κΈ°ν λ°μ΄ν°λ₯Ό ν¬ν¨μν¬ μ μλ νκ³λ‘ μ€λ¬΄μμλ μ¬μ©νκΈ° μ΄λ €μ (κ΄κ³ν λ°μ΄ν°λ² μ΄μ€ ν μ΄λΈμ N:N κ΄κ³ μ€κ³κ° λΆκ°λ₯νλ―λ‘ μν°ν°μ ν μ΄λΈ λΆμΌμΉ λ¬Έμ λ λ°μ)
μ°κ²° ν μ΄λΈμ© μν°ν°λ₯Ό μΆκ°νλ λ°©λ² μ¬μ©
@ManyToMany -> @OneToMany, @ManyToOne λ‘ νμ΄μ μ¬μ©νμ.

Member.java
MemberProduct.java
id λμ (member, product)λ₯Ό λ¬Άμ΄μ PK, FKλ‘ μ¬μ©ν μλ μμ§λ§,
ν₯ν λΉμ¦λμ€μ μΈ μ‘°κ±΄μ΄ μΆκ°λ κ²½μ°λ₯Ό κ³ λ €νλ©΄, GeneratedValue IDλ₯Ό μ¬μ©νλ κ²μ΄ λ μ μ°νκ³ κ°λ°μ΄ μ¬μμ§λ μ₯μ μ΄ μμ
Product.java
κ³ κΈ λ§€ν
μμκ΄κ³ λ§€ν
κ°μ²΄μ μμ ꡬ쑰μ DBμ μνΌ/μλΈνμ κ΄κ³λ₯Ό λ§€ν
DB μνΌ/μλΈνμ λ Όλ¦¬ λͺ¨λΈμ 물리 λͺ¨λΈλ‘ ꡬννλ λ°©λ²
@DiscriminatorColumn(name=βDTYPEβ) / μμ νμ νλ μ¬μ© (default. DTYPE)
@DiscriminatorValue(βXXXβ) / μμ νμ λͺ μμ μ (default. entity name)
@Inheritance(strategy=InheritanceType.XXX) / μμ νμ
μ‘°μΈ μ λ΅ JOINED

κΈ°λ³Έ μ μμΌλ‘ μ¬μ©
μ₯μ
ν μ΄λΈ μ κ·ν (μ μ₯κ³΅κ° ν¨μ¨ν)
μΈλν€ μ°Έμ‘° λ¬΄κ²°μ± μ μ½μ‘°κ±΄ νμ©
λ¨μ
μ‘°ν μΏΌλ¦¬κ° λ³΅μ‘ν΄μ§κ³ , μ‘°μΈμ λ§μ΄ μ¬μ©νκ² λμ΄ μ±λ₯ μ ν
λ°μ΄ν° μ μ₯ μ INSERT Query λ λ² νΈμΆ
λ¨μΌ ν
μ΄λΈ μ λ΅ SINGLE_TABLE

λ¨μνκ³ νμ₯ κ°λ₯μ±μ΄ μμ κ²½μ° μ¬μ©
μ₯μ
μ‘°ν μ μ‘°μΈμ΄ νμ μμΌλ―λ‘ μΌλ°μ μΌλ‘ μ‘°ν μ±λ₯μ΄ λΉ λ₯΄κ³ λ¨μ
λ¨μ
μμ μν°ν°κ° λ§€νν 컬λΌμ λͺ¨λ null νμ©
λ¨μΌ ν μ΄λΈμ λ§μ νλλ₯Ό μ μ₯νλ―λ‘ ν μ΄λΈμ΄ μ»€μ§ μ μκ³ , μν©μ λ°λΌ μ‘°ν μ±λ₯μ΄ μ νλ μ μμ
ꡬν ν΄λμ€λ§λ€ ν
μ΄λΈ μ λ΅ TABLE_PER_CLASS
λΆλͺ¨ ν΄λμ€λ μΆμ(abstract) ν΄λμ€λ‘ μμ±

μ μ§ λ³΄μ λ° κ΄λ¦¬ μ΅μ μΌλ‘ λΉμΆνλ μ λ΅..
μ₯μ
μλΈ νμ μ λͺ ννκ² κ΅¬λΆν΄μ μ²λ¦¬νκΈ° ν¨κ³Όμ
not null μ μ½μ‘°κ±΄ μ¬μ© κ°λ₯
λ¨μ
μμ ν μ΄λΈμ ν¨κ» μ‘°νν λ μ±λ₯ μ ν(UNION Query)
μμ ν μ΄λΈμ ν΅ν©ν΄μ 쿼리λ₯Ό μμ±νκΈ° μ΄λ €μ
.
@MappedSuperclass
κ³΅ν΅ λ§€ν μ λ³΄κ° νμν κ²½μ° μ¬μ©
μΆμ ν΄λμ€ κΆμ₯(μ§μ μμ±ν΄μ μ¬μ©ν μΌμ΄ μμ)
ex. λ±λ‘μΌ, μμ μΌ, λ±λ‘μ, μμ μ λ±..
ν·κ°λ¦¬μ§ μκΈ°!
μμκ΄κ³ λ§€νX - μμ ν΄λμ€μ λ§€ν μ λ³΄λ§ μ 곡)
μν°ν°/ν μ΄λΈ λ§€νX - μ‘°ν, κ²μ(em.find(BaseEntity)) λΆκ°
νλ‘μ & μ°κ΄κ΄κ³ κ΄λ¦¬
νλ‘μ
DB μ‘°νλ₯Ό 미루λ(Lazy) κ°μ§(Proxy) μν°ν° κ°μ²΄ μ‘°ν
em.getReference()
μ€μ ν΄λμ€λ₯Ό μμ λ°μ λ§λ€μ΄μ§κ³ , μ€μ μ κ² λͺ¨μλ§ κ°μ λΉ κΉ‘ν΅
μ€μ μν°ν°μ μ°Έμ‘°(target)λ₯Ό 보κ΄νκ³ , νλ‘μ λ©μλλ₯Ό νΈμΆνλ©΄ μ€μ μν°ν° λ©μλλ₯Ό νΈμΆ
νλ‘μ κ°μ²΄ νΉμ§

νλ‘μ κ°μ²΄λ μ²μ μ¬μ©ν λ
ν λ²λ§μ΄κΈ°νμ΄κΈ°ν μ νλ‘μ κ°μ²΄λ₯Ό ν΅ν΄ μ€μ μν°ν°μ μ κ·Ό κ°λ₯
νλ‘μ κ°μ²΄λ μλ³Έ μν°ν°λ₯Ό μμλ°μΌλ―λ‘, νμ μ²΄ν¬ μ instance of μ¬μ©
ν μμμ± μ»¨ν μ€νΈ μμμ λμΌν ID μ‘°ν μ,
JPAλ νμ κ°μ νμ μ μν°ν°λ₯Ό λ°νμμμ± μ»¨ν μ€νΈμ μ°Ύλ μν°ν°κ° μ΄λ―Έ μλ€λ©΄, em.getReference()λ₯Ό νΈμΆν΄λ μ€μ μν°ν°λ₯Ό λ°ν
λ°λλ‘ νλ‘μ μ‘°ν ν, μν°ν° μ‘°νλ₯Ό ν΄λ μ€μ μν°ν°κ° μλ porxy λ°ν
μ€μμ μνμΌ λ(em.clear() / em.close() / em.detach()), νλ‘μλ₯Ό μ΄κΈ°ννλ©΄
LazyInitializationExceptionλ°μ
μ¦μ λ‘λ©κ³Ό μ§μ° λ‘λ©
μ¦μ λ‘λ©
μ°κ΄ κ°μ²΄λ₯Ό μ‘°μΈμΌλ‘ ν¨κ» μ‘°ν
μ§μ° λ‘λ©
μ°κ΄ κ°μ²΄λ₯Ό νλ‘μλ‘ μ‘°ν
νλ‘μ λ©μλλ₯Ό νΈμΆνλ μμ μ μ΄κΈ°ν(μ‘°ν)
μ¦μ/μ§μ° λ‘λ© μ£Όμ μ¬ν
μ€λ¬΄μμλ
μ§μ° λ‘λ©λ§ μ¬μ©νμμ¦μ λ‘λ© μ μ© μ, μ°κ΄ κ΄κ³κ° λ§μμ§κ² λλ©΄ μμνμ§ λͺ»ν SQL λ°μ
λν, JPQLμμ N+1 λ¬Έμ λ°μ
N+1 λ¬Έμ ν΄κ²°μ JPQL fetch join νΉμ Entity Graph κΈ°λ₯μ μ¬μ©νμ.
@ManyToOne, @OneToOneμ defaultλ μ¦μ λ‘λ©μ΄λ―λ‘ LAZY μ€μ νμ
@OneToMany, @ManyToMany default : μ§μ° λ‘λ©
μμμ± μ μ΄
CASCADE
νΉμ μν°ν°λ₯Ό μμ μνλ‘ λ§λ€ λ, μ°κ΄λ μν°ν°λ ν¨κ» μμ μνλ‘ λ§λ€κ³ μΆμ κ²½μ° μ¬μ©
μ°κ΄κ΄κ³λ₯Ό λ§€ννλ κ²κ³Όλ μ무 κ΄λ ¨ μμ.
μν°ν°μ μμ μκ° νλμΌ λ(λ¨μΌ μν°ν°μ μ’ μμ , λΌμ΄ν μ¬μ΄ν΄μ΄ μ μ¬)λ§ μ¬μ©νκΈ°.
μ¬λ¬ μν°ν°μμ κ΄λ¦¬λλ κ²½μ° μ¬μ© X! (κ΄λ¦¬κ° νλ€μ΄μ§λ€..)
μ’ λ₯ (λ³΄ν΅ ALL, PERSIST, REMOVE μμμ μ¬μ©νλ©° λΌμ΄ν μ¬μ΄ν΄μ λμΌνκ² μ μ§)
ALL: λͺ¨λ μ μ©PERSIST: μμREMOVE: μμ MERGE: λ³ν©
REFRESH: REFRESH
DETACH: DETACH
κ³ μ κ°μ²΄
λΆλͺ¨ μν°ν°μ μ°κ΄κ΄κ³κ° λμ΄μ§ μμ μν°ν°
μ°Έμ‘°κ° μ κ±°λ μν°ν°λ λ€λ₯Έ κ³³μμ μ°Έμ‘°νμ§ μλ κ³ μ κ°μ²΄λ‘ λ³΄κ³ μμ
κ³ μ κ°μ²΄ μ κ±° μ€μ :
orphanRemoval = trueμμμ± μ μ΄μ λμΌνκ² νΉμ μν°ν°κ° κ°μΈ μμ ν λλ§ μ¬μ©νκΈ°
@OneToOne, @OneToManyλ§ μ¬μ© κ°λ₯
λΆλͺ¨ μν°ν°λ₯Ό μ κ±°ν λ CascadeType.REMOVEμ λμΌνκ² μμλ ν¨κ» μ κ±°
μμμ± μ μ΄μ ν¨κ» μ¬μ©ν κ²½μ° (CascadeType.ALL + orphanRemovel=true)
λΆλͺ¨ μν°ν°λ₯Ό ν΅ν΄ μμμ μλͺ μ£ΌκΈ° κ΄λ¦¬ κ°λ₯
DDD Aggregate Root κ°λ μ ꡬνν λ μ μ©
JPA Data Type
μν°ν° νμ
@Entityλ‘ μ μνλ κ°μ²΄
λ°μ΄ν°κ° λ³ν΄λ μλ³μλ‘ μΆμ κ°λ₯
κ° νμ
μλ³μκ° μμΌλ―λ‘ κ° λ³κ²½ μ μΆμ λΆκ°
μλͺ μ£ΌκΈ°λ₯Ό μν°ν°μ μμ‘΄
λ°μ΄ν° 곡μ X!
κΈ°λ³Έκ° νμ
Java Basic Type : int, double..
Wrapper Class : Integer, Long..
String
μλ² λλ νμ
컬λ μ κ° νμ
μμ νκ² λΆλ³ κ°μ²΄λ‘ λ§λ€κΈ°
Embedded Type
μλ‘μ΄ κ° νμ μ μ (κΈ°λ³Έ κ° νμ μ λͺ¨μμ λ§λ
λ³΅ν© κ° νμ)@Embeddable: κ° νμ μ μ@Embedded: κ° νμ μ¬μ©
μ₯μ
κ° νμ μ κ°μ²΄μ§ν₯μ μΌλ‘ μ¬μ© (μ¬μ¬μ©, λμ μμ§λ ..)
μλ² λλ νμ ν΄λμ€λ§μ΄ μ¬μ©νλ μ μ©ν λ©μλ μμ±
μλ² λλ νμ μ μμ ν μν°ν°μ μλͺ μ£ΌκΈ°λ₯Ό μμ‘΄
νΉμ§
μ μ€κ³λ ORM Applicationμ λ§€νν ν μ΄λΈ μλ³΄λ€ ν΄λμ€ μκ° λ λ§μ
ν μν°ν°μμ κ°μ μλ² λλ νμ μ μ¬μ©νμ¬ μ»¬λΌλͺ μ΄ μ€λ³΅λ κ²½μ°
@AttributeOverrides,@AttributeOverrideλ₯Ό μ¬μ©ν΄μ 컬λ¬λͺ μμ± μ¬μ μ
μλ² λλ νμ μ κ°μ΄ nullμ΄λ©΄, λ§€ν μ»¬λΌ κ° λͺ¨λ null
κ° νμ
λΆλ³ κ°μ²΄
κ° νμ μ μ¬λ¬ μν°ν°μμ 곡μ νλ©΄ Side Effect(λΆμμ©) λ°μ
μΈμ€ν΄μ€ κ°μ 곡μ νλ κ²μ μννλ―λ‘
κ°μ 볡μ¬ν΄μ μ¬μ©νκΈ°
κ° νμ μ λΆλ³ κ°μ²΄λ‘ μ€κ³νμ¬ κ°μ²΄ νμ μ μμ ν μ μκ² λ§λ€κΈ°λΆλ³ κ°μ²΄: μμ± μμ λ₯Ό μ μΈνκ³ κ°μ λ³κ²½ν μ μλ κ°μ²΄
μμ±μλ‘λ§ κ°μ μ€μ νκ³ , Setterλ μμ±νμ§ μκΈ°
Integer, Stringμ μλ°κ° μ 곡νλ λνμ μΈ λΆλ³ κ°μ²΄
κ° νμ λΉκ΅
κ° νμ λΉκ΅λ
equalsλ₯Ό μ¬μ©ν λλ±μ± λΉκ΅λ₯Ό μ¬μ©λμΌμ±(identity) λΉκ΅: μΈμ€ν΄μ€ μ°Έμ‘° κ° λΉκ΅
==λλ±μ±(equivalence) λΉκ΅: μΈμ€ν΄μ€ κ° λΉκ΅
equals()
κ° νμ μ equals() λ©μλλ₯Ό μ μ νκ² μ¬μ μ
νλ‘μ μ¬μ©μ κ³ λ €νμ¬ getter() μ¬μ© μΆμ²
κ° νμ 컬λ μ
κ° νμ μ νλ μ΄μ μ μ₯ν κ²½μ° μ¬μ©μ λ νΈ λ°μ€μ κ°μ΄ κ° λ³κ²½μ΄ νμ μλ λ¨μν κ²½μ° μ¬μ©
@ElementCollection,@CollectionTable
λ°μ΄ν°λ² μ΄μ€λ 컬λ μ μ κ°μ ν μ΄λΈμ μ μ₯ν μ μμΌλ―λ‘, λ³λμ ν μ΄λΈμ΄ νμ
κ° νμ 컬λ μ μ μν°ν°μ μλͺ μ£ΌκΈ°κ° κ°μ (Casecade.ALL + orphanRemoval=true)
μ μ₯
μ‘°ν
default. FetchType.LAZY μ λ΅ μ¬μ©
μμ
κ° νμ 컬λ μ μ μ μ½
κ° νμ 컬λ μ μ μν°ν°μ λ€λ₯΄κ²
μλ³μ κ°λ μ΄ μμΌλ―λ‘ λ³κ²½ μ μΆμ μ΄ μ΄λ €μ΄ ν° λ¨μ μ‘΄μ¬λ³κ²½ μ¬νμ΄ λ°μνλ©΄, μ£ΌμΈ μν°ν°μ μ°κ΄λ λͺ¨λ λ°μ΄ν°λ₯Ό μμ νκ³ , κ° νμ 컬λ μ μ μλ λͺ¨λ κ°μ λ€μ μ μ₯νλ λΉν¨μ¨μ μΈ λμ(μλ³μκ° μμΌλ―λ‘..)
κ° νμ 컬λ μ μ λ§€ννλ ν μ΄λΈμ λͺ¨λ 컬λΌμ λ¬Άμ΄μ κΈ°λ³Έ ν€λ‘ ꡬμ±ν΄μΌ ν¨
κ²°λ‘ μ μΌλ‘, μ λ νΈ λ°μ€μ κ°μ΄ λ³κ²½μ΄ νμ μλ λ¨μν κ²½μ°κ° μλλΌλ©΄, κ° νμ 컬λ μ λμ μΌλλ€ λ¨λ°©ν₯ κ΄κ³λ₯Ό μΆμ² (μλ³μ, μ§μμ μΈ κ° μΆμ , λ³κ²½μ΄ νμν κ²½μ°)
κ°μ²΄μ§ν₯ 쿼리 μΈμ΄
JPQL (Java Persistence Query Language)
SQLμ μΆμνν κ°μ²΄ μ§ν₯ 쿼리 μΈμ΄(νΉμ λ°μ΄ν°λ² μ΄μ€μ μμ‘΄ X)
ν μ΄λΈμ΄ μλ μν°ν° κ°μ²΄λ₯Ό λμμΌλ‘ 쿼리
λ¬Έμλ‘ JPQLμ΄ μμ±λλ€λ³΄λ λμ 쿼리 μμ±μ΄ μ΄λ €μ΄ λ¨μ
QueryDSL
λ¬Έμκ° μλ μλ°μ½λλ‘ JPQL μμ±
μ»΄νμΌ μμ μ λ¬Έλ² μ€λ₯ 체ν¬s
νΈλ¦¬ν λμ 쿼리 μμ±
JPQL λΉλ μν
λ€μ΄ν°λΈ SQL
JPQLλ‘ ν΄κ²°ν μ μλ νΉμ λ°μ΄ν°λ² μ΄μ€μ μμ‘΄μ μΈ κΈ°λ₯ μ¬μ© μ SQLμ μ§μ μμ±
κΈ°ν
JPAλ₯Ό μ¬μ©νλ©΄μ JDBC API, SpringJdbcTemplate, MyBatis λ±μ ν¨κ» μ¬μ© κ°λ₯
λ¨, μμμ± μ»¨ν μ€νΈλ₯Ό μ μ ν μμ (SQLμ μ€ννκΈ° μ§μ )μ κ°μ νλ¬μ νμ (em.flush())
κΈ°λ³Έ λ¬Έλ²
λ°ν νμ
TypeQuery: λ°ν νμ μ΄ λͺ νν λ μ¬μ©Query: λ°ν νμ μ΄ λͺ ννμ§ μμ λ μ¬μ©
μ‘°ν
query.getResultList(): κ²°κ³Όκ° νλ μ΄μμΌ κ²½μ° (리μ€νΈ λ°ν)κ²°κ³Όκ° μμΌλ©΄ λΉ λ¦¬μ€νΈ λ°ν
query.getSingleResult(): κ²°κ³Όκ° μ νν νλμΌ κ²½μ° (λ¨μΌ κ°μ²΄ λ°ν)κ²°κ³Όκ° μμΌλ©΄: javax.persistence.NoResultException
λ μ΄μμ΄λ©΄: javax.persistence.NonUniqueResultException
νλΌλ―Έν° λ°μΈλ©
νλ‘μ μ
SELECT μ μ μ‘°νν λμμ μ§μ νλ λ°©μ
μν°ν° νλ‘μ μ , μλ² λλ νμ νλ‘μ μ , μ€μΉΌλΌ νμ νλ‘μ μ
μ€μΉΌλΌ νμ νλ‘μ μ μ κ²½μ° μ¬λ¬ κ° μ‘°ν μ DTO μ‘°ν μΆμ²
νμ΄μ§
setFirstResult(int startPosition) : μ‘°ν μμ μμΉ
setMaxResults(int maxResult) : μ‘°νν λ°μ΄ν° μ
μ‘°μΈ
λ΄λΆ μ‘°μΈ:
SELECT m FROM Member m
[INNER] JOINm.team t
μΈλΆ μ‘°μΈ
SELECT m FROM Member m
LEFT [OUTER] JOINm.team t
μΈν μ‘°μΈ
select count(m)
from Member m, Team twhere m.username = t.name
.
Join On (JPA 2.1, Hibernate 5.1 μ΄μ)
μ‘°μΈ λμ νν°λ§
SELECT m, t FROM Member m LEFT JOIN m.team t
on t.name = 'A'
μ°κ΄κ΄κ³κ° μλ μν°ν° μΈλΆ μ‘°μΈ
SELECT m, t FROM Member m LEFT JOIN Team t
on m.username = t.name
μλΈ μΏΌλ¦¬
μ§μ ν¨μ
[NOT] EXISTS (Subquery): μλΈμΏΌλ¦¬μ κ²°κ³Όκ° μ‘΄μ¬νλ©΄ μ°Έ
{ALL | ANY | SOME} (Subquery)
ALL: λͺ¨λ λ§μ‘±νλ©΄ μ°Έ
ANY, SOME: 쑰건μ νλλΌλ λ§μ‘±νλ©΄ μ°Έ
[NOT] IN (Subquery): μλΈμΏΌλ¦¬μ κ²°κ³Ό μ€ νλλΌλ κ°μ κ²μ΄ μμΌλ©΄ μ°Έ
.
νκ³
JPAλ WHERE, HAVING μ μμλ§ μλΈ μΏΌλ¦¬ μ¬μ© κ°λ₯
Hibernateλ₯Ό μ¬μ©ν κ²½μ° SELECT μ λ κ°λ₯
FROM μ μ μλΈ μΏΌλ¦¬λ νμ¬ JPQLμμ λΆκ°λ₯ (μ‘°μΈμΌλ‘ νμ΄λ³΄κΈ°)
νμ νν
λ¬Έμ: 'She''s'μ«μ: 10L(Long), 10D(Double), 10F(Float)Boolean: true, falseENUM: jpql.MemberType.Admin (ν¨ν€μ§λͺ ν¬ν¨) or query.setParameter()μν°ν° νμ: μμ κ΄κ³μμ μ¬μ©μ‘°ν λμμ νΉμ μμμΌλ‘ νμ
νμ μΊμ€ν
COALESCE: νΉμ 컬λΌμ΄ NullμΌ κ²½μ° λ체 κ° λ°νNULLIF: μ§μ λ λ μμ΄ κ°μΌλ©΄ Null λ°ν
μ€κΈ λ¬Έλ²
κ²½λ‘ ννμ
μν νλ(m.username): κ²½λ‘ νμμ μ’ μ (νμ λΆκ°)λ¨μΌ κ° μ°κ΄ κ²½λ‘(m.team): 묡μμ λ΄λΆ μ‘°μΈ(inner join) λ°μ (νμ κ°λ₯)컬λ μ κ° μ°κ΄ κ²½λ‘(m.orders): 묡μμ λ΄λΆ μ‘°μΈ λ°μ (νμ λΆκ°)λͺ μμ μ‘°μΈμ ν΅ν΄ λ³μΉμΌλ‘ νμ κ°λ₯
.
λͺ μμ μ‘°μΈ: JOIN ν€μλλ₯Ό μ§μ μ¬μ©μ‘°μΈμ΄ λ°μνλ μν©μ ν λμ νμ ν μ μμ΄μ 쿼리 νλμ΄ νΈλ¦¬
μ‘°μΈμ SQL νλμ μ€μν ν¬μΈνΈμ΄λ―λ‘, κ°κΈμ λͺ μμ μ‘°μΈμ μ¬μ©νμ !!
묡μμ μ‘°μΈ: κ²½λ‘ ννμμ μν΄ λ¬΅μμ μΌλ‘ μ‘°μΈ λ°μλ΄λΆ μ‘°μΈλ§ κ°λ₯
μ‘°μΈ μΏΌλ¦¬λ₯Ό νμ νκΈ° μ΄λ €μ
μν°ν° μ§μ μ¬μ©
JPQLμμ μν°ν°λ₯Ό μ§μ μ¬μ©νλ©΄ SQLμμ ν΄λΉ μν°ν°μ κΈ°λ³Έ ν€ κ°μ μ¬μ©
Named Query
미리 μ μν΄λκ³ μ¬μ©νλ JPQL μ μ 쿼리
μ ν리μΌμ΄μ λ‘λ© μμ μ 쿼리 κ²μ¦ λ° μΊμ± ν μ¬μ¬μ©
λ²ν¬ μ°μ°
ν λ²μ μΏΌλ¦¬λ‘ μ¬λ¬ μν°ν° λ³κ²½ (UPDATE, DELETE)
executeUpdate()λ‘ μν₯μ λ°μ μν°ν° μ νμΈ κ°λ₯
λ²ν¬ μ°μ°μ
μμμ± μ»¨ν μ€νΈλ₯Ό 무μνκ³ λ°μ΄ν°λ² μ΄μ€μ μ§μ 쿼리λ₯Ό μ λ¬νλ―λ‘λ²ν¬ μ°μ°μ λ¨Όμ μ€ννκ±°λ
λ²ν¬ μ°μ° μν ν μμμ± μ»¨ν μ€νΈ μ΄κΈ°ν (em.clear())
νμΉ μ‘°μΈ
Fetch Join
JPQL
μ±λ₯ μ΅μ νλ₯Ό μν΄ μ 곡쿼리 ν λ²μ
μ°κ΄λ μν°ν°λ 컬λ μ μ ν¨κ» μ‘°ν(μ¦μ λ‘λ© μ°μ μ μ©)μΌλ° μ‘°μΈμμλ μ°κ΄λ μν°ν°λ₯Ό ν¨κ» μ‘°ννμ§ μμ
N + 1 μ΄μμ ν΄κ²° λ°©λ²
[ LEFT [OUTER] / INNER ] JOIN FETCH
Collection Fetch Join
μΌλλ€ κ΄κ³μμμ νμΉ μ‘°μΈ
μΌλλ€ κ΄κ³μμμ N+1 λ¬Έμ λ
batchSize μ€μ μΌλ‘ ν΄κ²° κ°λ₯LAZY λμ μ, IN μΏΌλ¦¬λ‘ size λ§νΌ ν λ²μ μ‘°ν
κ°λ³ μ±μ
Global μ€μ
SQL
DISTINCT
JPQLμμ DISTINCTκ° μ 곡νλ κΈ°λ₯
쿼리μ DISTINCT μΆκ°
μ ν리μΌμ΄μ μμ μ€λ³΅ μν°ν° μ κ±°
νκ³
νμΉ μ‘°μΈ λμμλ λ³μΉ λΆκ°
κ°μ²΄ κ·Έλν μ¬μ(Nμ ν΄λΉνλ λͺ¨λ λ°μ΄ν° μ‘°νλ₯Ό κΈ°λ)κ³Ό λ§μ§ μμ
t.membersμμ 쑰건μ κ±Έκ³ μΆλ€λ©΄, memberλ₯Ό selectμ μμ μ¬μ©νμ.
컬λ μ μ ν κ°λ§ νμΉ μ‘°μΈ κ°λ₯
컬λ μ νμΉ μ‘°μΈμ νλ©΄ νμ΄μ§ API μ¬μ© λΆκ°
λ¨μΌ κ° μ°κ΄ νλ(1:1/N:1)λ νμΉ μ‘°μΈμ ν΄λ νμ΄μ§ κ°λ₯
컬λ μ νμΉ μ‘°μΈμΌλ‘ 컬λ μ λ°μ΄ν°κ° μ리λ νμ λ°μ
Last updated