이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편]을 수강하며 정리한 글입니다.
👉 기본 환경
- Language: Java
- DB: H2 Database
- IDE: IntelliJ
⌨️ 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public class Main {
public static void main(String[] args) {
// 생략
try {
Address address = new Address("city", "street", "zipcode");
MemberUsingEm memberUsingEm1 = new MemberUsingEm();
memberUsingEm1.setUsername("hello1");
memberUsingEm1.setHomeAddress(address);
em.persist(memberUsingEm1);
MemberUsingEm memberUsingEm2 = new MemberUsingEm();
memberUsingEm2.setUsername("hello2");
memberUsingEm2.setHomeAddress(address);
em.persist(memberUsingEm2);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
|
🖨️발생한 쿼리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
🚨 memberUsingEm2의 city를 변경하고자 할 때, setter를 활용하면 side effect 발생
⌨️ 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public class Main {
public static void main(String[] args) {
// 생략
try {
Address address = new Address("city", "street", "zipcode");
MemberUsingEm memberUsingEm1 = new MemberUsingEm();
memberUsingEm1.setUsername("hello1");
memberUsingEm1.setHomeAddress(address);
em.persist(memberUsingEm1);
MemberUsingEm memberUsingEm2 = new MemberUsingEm();
memberUsingEm2.setUsername("hello2");
memberUsingEm2.setHomeAddress(address);
em.persist(memberUsingEm2);
memberUsingEm2.getHomeAddress().setCity("newCity");
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
|
🖨️발생한 쿼리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* update
jpa_basic.MemberUsingEm */ update
MemberUsingEm
set
city=?,
street=?,
zipcode=?,
username=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIPCODE=?,
endDate=?,
startDate=?
where
id=?
Hibernate:
/* update
jpa_basic.MemberUsingEm */ update
MemberUsingEm
set
city=?,
street=?,
zipcode=?,
username=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIPCODE=?,
endDate=?,
startDate=?
where
id=?
|
memberUsingEm1의 city도 newCity로 update 발생
🤓 해결 방안: 새로운 Address 객체 생성
⌨️ 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public class Main {
public static void main(String[] args) {
// 생략
try {
Address address = new Address("city", "street", "zipcode");
MemberUsingEm memberUsingEm1 = new MemberUsingEm();
memberUsingEm1.setUsername("hello1");
memberUsingEm1.setHomeAddress(address);
em.persist(memberUsingEm1);
Address newAddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());
MemberUsingEm memberUsingEm2 = new MemberUsingEm();
memberUsingEm2.setUsername("hello2");
memberUsingEm2.setHomeAddress(newAddress);
em.persist(memberUsingEm2);
memberUsingEm2.getHomeAddress().setCity("newCity");
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
|
🖨️발생한 쿼리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* update
jpa_basic.MemberUsingEm */ update
MemberUsingEm
set
city=?,
street=?,
zipcode=?,
username=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIPCODE=?,
endDate=?,
startDate=?
where
id=?
|
⭐ 객체 타입을 수정할 수 없게 만들어 부작용을 차단
▶ 값 타입을 immutable object로 설계
= 생성자로만 값을 설정하고, Setter를 만들지 않는 방법
* immutable object: 생성 시점 이후, 절대 값을 변경할 수 없는 객체
😮 값을 변경하고 싶을 경우에는 Setter가 아닌 새로운 Address 객체를 생성해야 함
⌨️ 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class Main {
public static void main(String[] args) {
// 생략
try {
Address address = new Address("city", "street", "zipcode");
MemberUsingEm memberUsingEm1 = new MemberUsingEm();
memberUsingEm1.setUsername("hello1");
memberUsingEm1.setHomeAddress(address);
em.persist(memberUsingEm1);
Address newAddress = new Address("newCity", address.getStreet(), address.getZipcode());
memberUsingEm1.setHomeAddress(newAddress);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
emf.close();
}
}
|
🖨️발생한 쿼리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
Hibernate:
/* insert jpa_basic.MemberUsingEm
*/ insert
into
MemberUsingEm
(city, street, zipcode, username, WORK_CITY, WORK_STREET, WORK_ZIPCODE, endDate, startDate, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* update
jpa_basic.MemberUsingEm */ update
MemberUsingEm
set
city=?,
street=?,
zipcode=?,
username=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIPCODE=?,
endDate=?,
startDate=?
where
id=?
|
🤓 em.persist(memberUsingEm1); 이후, 변경된 address를 persist 또는 update하지 않아도 DB에 반영되는 이유
em.persist(memberUsingEm1)를 호출하면 memberUsingEm1 엔티티가 영속성 컨텍스트에 등록
→ 이후 엔티티의 필드 값을 변경하면 JPA는 변경사항을 자동으로 감지
→ 트랜잭션을 커밋할 때, JPA는 영속성 컨텍스트에 있는 엔티티의 변경사항을 DB에 반영
* JPA의 더티 체킹(Dirty Checking)
영속성 컨텍스트가 엔티티의 원래 상태와 현재 상태를 비교하여 변경된 필드를 감지하고, 변경사항을 자동으로 DB에 반영
📚 참고 자료
'Java > JPA' 카테고리의 다른 글
[JPA_Basic] 프로젝션 - 여러 값 조회 (1) | 2023.09.22 |
---|---|
[JPA_Basic] 값 타입 컬렉션 (0) | 2023.09.19 |
[JPA_Basic] Cascade (0) | 2023.09.11 |
[JPA_Basic] N+1 문제 (0) | 2023.09.10 |
[JPA_Basic] Proxy (0) | 2023.09.08 |