LAZY ์ ๋ต์ Proxy
๐ฌ Intro
LAZY ์ ๋ต์์ ์ฌ์ฉํ๋ Proxy์ ๋ํด ์์๋ด ์๋ค.
โ LAZY
- JPA ์ฐ๊ด๊ด๊ณ์์ ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ๊ฐ์ ธ์ฌ๋ ์ฌ์ฉํ๋ ์ ๋ต ์ค ํ๋์ด๋ค.
- ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์์ ์์ ์ค์ ์ํฐํฐ๋ฅผ ๊ฐ์ ธ์ค์ง ์๊ณ ํ๋ก์ ํํ๋ก ๊ฐ์ ธ์ค๊ฒ ๋๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์ฌ์ฉ๋๋ ์์ ์ ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ๋ค. ๋๋ฌธ์ N + 1 ๋ฌธ์ ๊ฐ ๋ฐ์ ํ ์ ์๋ค.
โ Proxy
- ์ค์ ์ํฐํฐ๊ฐ ์๋ ๊ฐ์ง ๊ฐ์ฒด์ด๋ค.
- ํ๋ก์ ๊ฐ์ฒด์ ์ด๊ธฐํ๋ ํ๋ฒ๋ง ์ผ์ด๋๋ค.
์ฌ์ฉ๋๋ ์์
orHibernate.initialize()
๋ฅผ ํตํด์ ์ด๊ธฐํ ๋๋ค. ์ด๊ธฐํ ๋ ๋ฐ์ดํฐ๋ ์์์ฑ ์ปจํ ์คํธ 1์ฐจ ์บ์์ ์ ์ฅ๋๋ค. - ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ด๊ธฐํ ๋๋๋ผ๋ ๊ฐ์ฒด์ ์ถ๊ฐ๋ก ์ฐ๊ด๋ ์ํฐํฐ์์ ์ฐ๊ด๊ด๊ณ ์ ๋ต์ด LAZY๋ผ๋ฉด ํด๋น ์ํฐํฐ๋ฅผ ํ๋ก์๋ก ๊ฐ์ ธ์จ๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์ ๋๋ก ์ค์ ๊ฐ์ฒด๋ก ๋ฐ๋์ง ์๋๋ค. ์ฆ, ์ด๊ธฐํ๊ฐ ๋๋๋ผ๋ ํ๋ก์ ๊ฐ์ฒด๋ก ๋จ๋๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์ฌ์ฉ๋๋ ์์ ์ DB์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํตํด DB์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ๋ ค๋ฉด ํธ๋์ญ์
์์ ์์ด์ผํ๋ค. ํธ๋์ญ์
์ด ์๋๋ฐ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํตํด์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ๋ ค๊ณ ํ๋ฉด
LazyInitializationException
์ด ๋ฐ์ํ๋ค.
๐ ์์
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
@Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_store_id")
private BookStore bookStore;
@Builder
public Book(final Long id, final String title, final String author, final BookStore bookStore) {
this.id = id;
this.title = title;
this.author = author;
this.bookStore = bookStore;
}
}
@Entity
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class BookStore {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Builder
public BookStore(final Long id, final String name) {
this.id = id;
this.name = name;
}
}
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
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
private final BookStoreRepository bookStoreRepository;
private final EntityManager em;
@Transactional
public BookStore getProxyBookStore() {
BookStore bookStore = BookStore.builder()
.name("ํ
์คํธ ๋ถ์คํ ์ด1")
.build();
Book book = Book.builder()
.title("ํ
์คํธ ๋ถ1")
.bookStore(bookStore)
.build();
bookStoreRepository.save(bookStore);
bookRepository.save(book);
// ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด DB์ ๋ด์ฉ์ ๋ฐ์ํ๊ณ , 1์ฐจ ์บ์๋ฅผ ์ง์ด๋ค.
em.flush();
em.clear();
// save๋ฅผ ํ๋ ์์ ์์ book์ id๊ฐ ์๋์ผ๋ก ํ ๋น ๋๋ค.
// ๋ฐ๋ผ์ 1์ฐจ ์บ์๋ฅผ ์ง์ฐ๋๋ผ๋ id๋ ์ด๋ฏธ ํ ๋น๋ ์ํ
Long bookId = book.getId();
// book๋ฅผ ๊ฐ์ ธ์ค๋ฉด LAZY ์ ๋ต์ ์ํด bookStore๋ ํ๋ก์ ๊ฐ์ฒด๋ก ๊ฐ์ ธ์์ง๋ค.
Book getBook = bookRepository.findById(bookId).orElse(null);
BookStore getBookStore = getBook.getBookStore();
/**
* ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ๋ก ์ด๊ธฐํํ๋ค. ๋ฐ๋ผ์ ์ค์ ๊ฐ์ฒด์ ํ์ํ ์ ๋ณด๋ฅผ ์ ๋ถ ๊ฐ์ ธ์จ๋ค.
* ๋ถ์คํ ์ด์ ์ถ๊ฐ๋ก ์ฐ๊ด๋ ์ํฐํฐ๋ค์ LAZY์ผ ๊ฒฝ์ฐ ํ๋ก์๋ก ๊ฐ์ ธ์ค๊ณ , EAGER๋ผ๋ฉด ์ฆ์ ๊ฐ์ ธ์จ๋ค.
*/
// Hibernate.initialize(getBookStore);
return getBookStore;
}
}
- ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด em.flush()๋ฅผ ํธ์ถํ์ฌ ์์์ฑ ์ปจํ ์คํธ์ ์์ธ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ณ , em.clear()๋ฅผ ํธ์ถฃํ์ฌ 1์ฐจ ์บ์๋ฅผ ์ง์ด๋ค.
- book์ id๋ saveํ๋ ์์ ์ ์ค์ ๊ฐ์ฒด์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ 1์ฐจ ์บ์๋ฅผ ์ง์๋ id ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
- findBy()๋ฅผ ํตํด ์ ์ฅํ book์ ๊ฐ์ ธ์ค๋ฉด ์ด์ ์ฐ๊ด๋ bookStore๋ LAZY ์ ๋ต์ ์ํด ํ๋ก์ ๊ฐ์ฒด๋ก ๊ฐ์ ธ์์ง๋ค.
Hibernate.initialize()
๋ฅผ ํตํด์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํํ ์ ์๋ค. ์ด๋ ํด๋น ์ํฐํฐ์ ํ์ํ ์ ๋ณด๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ค๊ฒ ๋๋ค. ๋ง์ฝ BookStore์ ์ ์ธ๋ ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ ์ ๋ต์ด LAZY๋ผ๋ฉด ์ฐ๊ด๋ ๊ฐ์ฒด๋ ํ๋ก์ ๊ฐ์ฒด๋ก, EAGER๋ผ๋ฉด ์ฐ๊ด๋ ์ํฐํฐ์ ์ค์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์จ๋ค.- ๊ฒฐ๊ณผ์ ์ผ๋ก getProxyBookStore() ๋ BookStore ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
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
53
@SpringBootTest
public class JpaTest6 {
@Autowired
private BookService bookService;
private BookStore proxyBookStore;
@BeforeEach
void setUp() throws Exception {
proxyBookStore = bookService.getProxyBookStore();
}
@DisplayName("LazyInitializationException ๋ฐ์ ์ฑ๊ณต ํ
์คํธ")
@Test
void proxyTest1() throws Exception {
// given
System.out.println("proxyBookStore : " + proxyBookStore.getClass());
System.out.println("BookStore : " + BookStore.class);
// when
// then
// ํ๋ก์ ๋ถ ์คํ ์ด๋ ํ๋ก์ ํ์
์ด๋ค.
assertThat(proxyBookStore).isInstanceOf(HibernateProxy.class);
// ํ๋ก์ ๋ถ ์คํ ์ด๋ ๋ถ ์คํ ์ด ์ธ์คํด์ค ํ์
์ด๋ค.
assertThat(proxyBookStore).isInstanceOf(BookStore.class);
// ํ๋ก์ ๋ถ ์คํ ์ด์ ํด๋์ค๋ ๋ถ์คํ ์ด ํด๋์ค์ ๋์ผํ์ง ์๋ค.
assertThat(proxyBookStore.getClass()).isNotEqualTo(BookStore.class);
assertThatThrownBy(() -> proxyBookStore.getName())
.isInstanceOf(LazyInitializationException.class);
}
@DisplayName("LazyInitializationException ๋ฐ์ ์คํจ ํ
์คํธ")
@Test
@Transactional
void proxyTest2() throws Exception {
//given
//when
//then
assertThat(proxyBookStore.getName()).isNotNull();
assertThat(Hibernate.isInitialized(proxyBookStore)).isTrue();
}
}
1
2
proxyBookStore : class com.example.jparemind1.domain1.BookStore$HibernateProxy$ULvIdbkE
BookStore : class com.example.jparemind1.domain1.BookStore
proxyTest1()
- getProxyBookStore()์์ ๋ฐํํ bookStore๋ฅผ ์ถ๋ ฅํด๋ณด๋ฉด ํ๋ก์ ๊ฐ์ฒด๋ผ๋๊ฒ์ ์ ์ ์๋ค.
- HibernateProxy.class๋ ํ๋ก์ ๊ฐ์ฒด ํ์ ์ด๋ค. ๋ฐ๋ผ์ bookStore๋ ํด๋น ํ์ ๊ณผ ๊ฐ๋ค.
- bookStore๋ ํ๋ก์ ๊ฐ์ฒด ์ด์ง๋ง ์ธ์คํด์ค ํ์ ์ BookStore.class์ ๊ฐ๋ค.
- ํ์ง๋ง ์ค์ bookStore์ ์ค์ class ๋ BookStore.class์ ๊ฐ์ง ์๋ค.
- ๋ฐ๋ผ์ ๋์ ๋น๊ต๋ โ==โ ๋์ผ์ฑ์ผ๋ก ํ๋ฉด ์๋๋ค.
proxyTest2()
- getProxyBookStore()์ ํธ๋์ญ์ ๊ณผ ํ ์คํธ proxyTest2()์ ํธ๋์ญ์ ์ด ๋ฌถ์ฌ ์๊ธฐ ๋๋ฌธ์ proxyTest2() ํ ์คํธ๊ฐ ๋๋๋ ์์ ์ ๋กค๋ฐฑ์ด ๋๋ค. ๋ฐ๋ผ์ ์ค์ ๋ก DB์ SELECT์ ์ ์ธํ ์ฟผ๋ฆฌ๋ ์คํ๋์ง ์๋๋ค.
- proxyBookStore๊ฐ getName()์ ํตํด ์ด๊ธฐํ ๋์๋ค. ๋ฐ๋ผ์
Hibernate.isInitialized()
๋ true๋ฅผ ๋ฐํํ๋ค.
โจ Summary
- LAZY ์ ๋ต์ ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ์ง์ฐ ๋ก๋ฉํ์ฌ ์ฒ์์ ํ๋ก์ ๊ฐ์ฒด๋ก ๊ฐ์ ธ์ค๊ณ , ์ค์ ์ฌ์ฉ ์ DB์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ๋ฐฉ์์ด๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ์ํฐํฐ๋ฅผ ๋๋ฆฌํ๋ฉฐ, ์ด๊ธฐํ๋ ๋๊น์ง๋ ๊ฐ์ง ๊ฐ์ฒด๋ก ๋จ์ ์๋ค. ์ด๊ธฐํ ํ์๋ ํ๋ก์ ๊ฐ์ฒด ์์ฒด๋ ์ค์ ์ํฐํฐ๋ก ๋ฐ๋์ง ์๋๋ค.
- Hibernate.initialize()๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ๋ก ์ด๊ธฐํํ์ฌ, ์ค์ ๋ฐ์ดํฐ๋ฅผ DB์์ ๊ฐ์ ธ์จ๋ค. ํธ๋์ญ์ ๋ด์์๋ง ์ด๊ธฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ๋์ผ์ฑ(==) ๋น๊ต๋ฅผ ํ๋ฉด ์๋๋ค. ํ๋ก์์ ํด๋์จ๋ ์ค์ ์ํฐํฐ ํด๋์ค์ ๋ค๋ฅด๋ค. ๋ฐ๋ผ์
instanceof
๋ก ๋น๊ตํด์ผํ๋ค. - ํธ๋์ญ์
๋ด์์ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ด๊ธฐํ ๋๋ฉด
LazyInitializationException
์ด ๋ฐ์ํ์ง ์๋๋ค.
This post is licensed under CC BY 4.0 by the author.