μ„œλ‘ 

ν”„λ‘œμ νŠΈλ₯Ό μ‹€ν–‰ν•˜λŠ” κ³Όμ •μ—μ„œ λ‹€μŒκ³Ό 같은 WARN λ©”μ‹œμ§€κ°€ 좜λ ₯됐닀. open-in-viewκ°€ ν™œμ„±ν™”λ˜μ–΄ μžˆλŠ”λ° 이러면 λ·° λ Œλ”λ§ 쀑에 λ°μ΄ν„°λ² μ΄μŠ€ 쿼리가 μˆ˜ν–‰λ  수 μžˆλ‹€. 이λ₯Ό λΉ„ν™œμ„±ν™”ν• λ €λ©΄ 섀정해라 둜 해석할 수 μžˆλ‹€. 처음 이 λ©”μ‹œμ§€λ₯Ό 봀을 λ•Œ, λ·° λ Œλ”λ§ 쀑에 쿼리가 λ°œμƒν•  수 μžˆλŠ” 것이 μ™œ WARN λ©”μ‹œμ§€μΈμ§€ 잘 λͺ°λžλ‹€. μ–΄λ–€ μœ„ν—˜μ„±μ΄ μžˆλŠ”μ§€ μ•Œμ•„λ΄€λ‹€.

λ³Έλ‘ 

μ •μ˜

open-in-viewλ₯Ό 톡해 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ 컀λ„₯μ…˜μ„ μ–Έμ œ λŒλ €μ£ΌλŠ”μ§€ μ„€μ •ν•  수 μžˆλ‹€κ³  ν•œλ‹€.

spring:
  jpa:
    open-in-view: /* true or false */
  • true : μ„œλ²„κ°€ ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 응닡 λ©”μ‹œμ§€λ₯Ό 보낸 이후에 컀λ„₯μ…˜μ„ λ°˜λ‚© (응닡을 ν•œ ν›„)
  • false : λ°μ΄ν„°λ² μ΄μŠ€ 컀λ„₯μ…˜μ˜ μ‚¬μš©μ΄ λλ‚˜λ©΄ λ°”λ‘œ λ°˜λ‚© (νŠΈλžœμž­μ…˜μ΄ λλ‚œ ν›„)
  • 컀λ„₯μ…˜μ„ λ°˜λ‚©ν•œλ‹€ = μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ λ‹«νžŒλ‹€λ‘œ 보면 μ΄ν•΄ν•˜κΈ° νŽΈν•  것 κ°™λ‹€.

true일 λ•Œ μ™œ λ¬Έμ œκ°€ 될까 ?

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹œμž‘λ  λ•Œ, λ°μ΄ν„°λ² μ΄μ…˜μ˜ 컀λ„₯μ…˜μ„ 미리 νšλ“ν•˜μ—¬ 컀λ„₯μ…˜ν’€μ— μ €μž₯을 ν•œλ‹€. 이λ₯Ό 톡해 μš”μ²­λ•Œλ§ˆλ‹€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ 컀λ„₯μ…˜μ„ νšλ“ν•˜λŠ” λΉ„μš©μ„ 쀄일 수 μžˆλ‹€. 컀λ„₯μ…˜ν’€μ— μ €μž₯λ˜λŠ” 컀λ„₯μ…˜μ˜ κΈ°λ³Έ κ°œμˆ˜λŠ” 주둜 10κ°œλΌκ³ ν•˜λ©°, 섀정을 톡해 λ³€κ²½ν•  수 μžˆλ‹€.

컀λ„₯μ…˜ν’€μ— μ €μž₯된 컀λ„₯μ…˜ 10κ°œκ°€ ν΄λΌμ΄μ–ΈνŠΈμ˜ ν˜ΈμΆœμ„ 톡해 λ°˜ν™˜λλ‹€κ³  가정을 ν•œλ‹€. 이쀑 컀λ„₯μ…˜μ˜ μ‚¬μš©μ΄ λλ‚˜ 더 이상 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 컀λ„₯μ…˜μ΄ μ‘΄μž¬ν•  것이닀.

이λ₯Ό λ°˜λ‚©ν•˜μ§€ μ•Šκ³  κ·ΈλŒ€λ‘œ κ°€μ§€κ³  μžˆλ‹€λ©΄, 이후에 λ“€μ–΄μ˜€λŠ” μš”μ²­μ€ λŒ€κΈ° μƒνƒœμ— μžˆκ±°λ‚˜ 컀λ„₯μ…˜μ„ νšλ“ν•˜κΈ° μœ„ν•΄ TCP 3handshakeλ₯Ό μ§„ν–‰ν•  것이닀. μ΄λ ‡κ²Œ 되면 ν΄λΌμ΄μ–ΈνŠΈμ˜ λŒ€κΈ° μ‹œκ°„μ΄ μ¦κ°€ν•˜κ³ , 컀λ„₯μ…˜μ„ νšλ“ν•˜κΈ° μœ„ν•œ λΉ„μš©μ΄ λ°œμƒν•œλ‹€.

그럼 false둜 μ„€μ •ν•΄μ•Ό ν• κΉŒ ?

μ—¬κΈ°μ„œλ„ λ¬Έμ œκ°€ λ°œμƒν•œλ‹€. true둜 섀정을 ν•΄μ„œ 컀λ„₯μ…˜ 풀을 λ°˜λ‚©μ„ ν•˜κ³ , AλΌλŠ” 데이터λ₯Ό κ°€μ Έμ™”λ‹€κ³  가정을 ν•œλ‹€. AλŠ” B와 연관관계λ₯Ό κ°€μ§€κ³  있고 μ§€μ—° λ‘œλ”© κΈ°λŠ₯을 μ‚¬μš©ν•œλ‹€.

Aλ₯Ό κ°€μ Έμ˜€κ³  commit이 되면, νŠΈλžœμž­μ…˜μ€ λ‹«νžˆκ³  컀λ„₯μ…˜ 풀도 λ°˜λ‚©μ΄ λœλ‹€. 이 μƒνƒœμ—μ„œ Bλ₯Ό μ‘°νšŒν•˜κ²Œ 되면 μ‘°νšŒκ°€ λ˜μ§€ μ•Šκ³  μ—λŸ¬κ°€ λ°œμƒλœλ‹€. μ™œλƒν•˜λ©΄, μ§€μ—° λ‘œλ”©μ€ 쑰회 λ‹Ήμ‹œμ—λŠ” ν”„λ‘μ‹œ 객체λ₯Ό μ§‘μ–΄ λ„£κ³  ν•„μš”ν•œ μˆœκ°„μ— 객체λ₯Ό μ‘°νšŒν•˜λŠ”λ° 컀λ„₯μ…˜ 풀이 λ°˜λ‚© 된 μ‹œμ μ—μ„œ ν”„λ‘μ‹œ 객체가 μ–΄λ–€ 객체의 ν”„λ‘μ‹œ 객체인지 μ•Œ 수 μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.

더 μžμ„Ένžˆ μ„€λͺ…ν•˜λ©΄, Aλ₯Ό κ°€μ Έμ˜€κ²Œ 되면 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 이λ₯Ό κ΄€λ¦¬ν•œλ‹€. νŠΈλžœμž­μ…˜μ΄ λλ‚˜λ²„λ €μ„œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ λ‹«νžˆκ²Œ 되면 AλŠ” μ€€μ˜μ† μƒνƒœλ‘œ λ³€ν•˜κ²Œ λœλ‹€. μ—¬κΈ°μ„œ A와 μ—°κ΄€ 관계가 μžˆλŠ” B의 ν”„λ‘μ‹œ 객체λ₯Ό 톡해 Bλ₯Ό μ‘°νšŒν• λ €κ³  ν•˜λ©΄ μ‘°νšŒκ°€ μ•ˆλœλ‹€. μ™œλƒν•˜λ©΄, μ—”ν‹°ν‹°κ°€ μ˜μ† μƒνƒœμ—¬μ•Ό μ‘°νšŒκ°€ κ°€λŠ₯ν•˜λ©° μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ λ‹«νžŒ μ‹œμ μ—μ„œ μ€€μ˜μ† μƒνƒœλ₯Ό μ˜μ† μƒνƒœλ‘œ λ°”κΏ€ 수 μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.

이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ΅œμ΄ˆμ— μ—΄λ¦° νŠΈλžœμž­μ…˜μ—μ„œ μ—°κ΄€ 관계가 μžˆλŠ” 데이터λ₯Ό λͺ¨λ‘ μ‘°νšŒν•΄μ•Ό ν•œλ‹€.

그럼 true와 false λ‘˜ 쀑 μ–΄λ–€κ±Έλ‘œ 섀정을 ν•΄μ•Ό ν• κΉŒ ?

정닡은 μ—†λŠ” 것 κ°™λ‹€. κ΅¬ν˜„ν•˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— 따라 섀정이 달라진닀고 생각을 ν–ˆλ‹€. true둜 μ„€μ •ν•˜λ©΄ 컀λ„₯μ…˜ν’€μ˜ κΈ°λ³Έ 크기λ₯Ό 크게 작고, false둜 μ„€μ •ν•˜λ©΄ νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ λͺ¨λ‘ μ²˜λ¦¬κ°€ λ˜κ±°λ‚˜ μ§€μ—° λ‘œλ”©μ„ μ‚¬μš©ν•œ 데이터λ₯Ό λͺ¨λ‘ λ‘œλ“œν•˜λŠ” λ‘œμ§μ„ κ΅¬μ„±ν•˜λ©΄ λœλ‹€.

ν”„λ‘œμ νŠΈ 적용

μœ μ €κ°€ 생성이 되면 μ‘λ‹΅μœΌλ‘œ μœ μ €μ˜ 역할이 κΈ°λ³Έκ°’μœΌλ‘œ λ‚˜μ™€μ•Όν•˜λŠ”λ°, null κ°’μœΌλ‘œ λ‚˜μ™€μ„œ 해결책을 찾던 쀑 머리 ν•œ ꡬ석에 있던 open-in-view 섀정이 생각이 났닀. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μœ μ§€λ˜λŠ” λ™μ•ˆ μ˜μ†λœ μœ μ € μ—”ν‹°ν‹°μ—λŠ” 역할이 null κ°’μ΄μ˜€λ‹€. open-in-viewλ₯Ό false둜 μ„€μ •ν•˜κ³ , λ‹€μŒκ³Ό 같이 μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ μœ μ €μ˜ 역할이 μ •μƒμ μœΌλ‘œ 좜λ ₯이 λœλ‹€.

@PostMapping("/user")
public ResponseEntity < ResponseUser > createUser(
    @Valid @RequestBody RequestCreateUser requestCreateUser
) {
    userService.createUser(requestCreateUser);
    ResponseUser user = userService.findUserByUsername(requestCreateUser.username());
    return ResponseEntity.ok(user);
}

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μœ μ§€λ˜λŠ” λ™μ•ˆμ— μœ μ €λ₯Ό κ²€μƒ‰ν•˜λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 쑰회λ₯Ό ν•œλ‹€. μ΄λ•ŒλŠ” 순수 μž…λ ₯된 κ°’μœΌλ‘œ κ΅¬μ„±λœ μœ μ €μ˜ μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ‘΄μž¬ν•œλ‹€.

생성이 λλ‚˜κ³  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό λ‹«κ³ , λ‹€μ‹œ 검색을 ν•˜κ²Œ 되면 μƒˆλ‘œ μ—΄λ¦° μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—λŠ” μœ μ € μ—”ν‹°ν‹°κ°€ μ—†κΈ° λ•Œλ¬Έμ— λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‘°νšŒν•΄μ„œ κ°€μ Έμ˜¨λ‹€. 그럼 기본값이 λͺ¨λ‘ λ“€μ–΄κ°„ μœ μ € μ—”ν‹°ν‹°λ₯Ό κ°€μ Έμ˜¬ 수 μžˆλ‹€.

마무리

이 λ‚΄μš©μ€ 사싀 JDBC ν•™μŠ΅ λ•Œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‹œμž‘ κ³Όμ •μ—μ„œ μ—λŸ¬ λ©”μ‹œμ§€κ°€ λ‚˜μ˜€κΈΈλ ˆ κΆκΈˆν•΄μ„œ ν•œ 번 μ°Ύμ•„λ΄€λ˜ λ‚΄μš©μ΄λ‹€. κ·Έ λ•ŒλŠ” 이런 λ‚΄μš©μ΄κ΅¬λ‚˜ ν•˜κ³  μΈμ§€ν•˜κ³  λ„˜μ–΄κ°”λŠ”λ°, ν”„λ‘œμ νŠΈ κ΅¬ν˜„ κ³Όμ •μ—μ„œ ν•„μš”ν•˜λ‹€κ³  μƒκ°λ˜μ„œ μ •λ¦¬ν–ˆλ‹€. 무심코 μ§€λ‚˜κ°„ λ‚΄μš©μ΄ 해결책이 됨을 μ•Œκ²Œ 됐고, μ‚¬μ†Œν•œ 것 ν•˜λ‚˜ν•˜λ‚˜λΌλ„ μ•Œμ•„λ‘˜ ν•„μš”κ°€ μžˆμŒμ„ μ•Œκ²Œ 됐닀.

이후 ν”„λ‘œμ νŠΈ μ§„ν–‰ κ³Όμ •μ—μ„œ μ§€μ—° λ‘œλ”©μ„ μ‚¬μš©ν•˜λŠ” 객체듀이 μ‘΄μž¬ν•¨μ„ μ•Œκ²Œ 됐고 또 λ‹€μ‹œ μ‚½μ§ˆμ„ ν•΄μ•Όν•œλ‹€λŠ” ν˜„μ‹€μ„ λ§ˆμ£Όν–ˆλ‹€. ν—ˆν—ˆν—ˆν—ˆ

μ°Έκ³  λ¬Έν—Œ

Spring Boot의 open-in-view, κ·Έ μœ„ν—˜μ„±μ— λŒ€ν•˜μ—¬. spring.jpa.open-in-view λž€? OSIV(Open Session in view)μ΄λž€? μž₯단점, 써야할지 말아야할지