๐ ๋ฌธ์ ์ํฉ (ํ ์คํธ ์ฝ๋์์๋ง ๋ฐ์ํ๋ ๋ฌธ์ ์!)
์๋์ ๊ฐ์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ์ฌ ํ์ธํด๋ณด๊ณ ์ ํจ
- Question Entity
public class Question {
// .
// .
@OneToMany (mappedBy = "question", cascade = CascadeType.REMOVE)
private List<Answer> answerList;
}
- Answer Entity
public class Answer {
// .
// .
@ManyToOne // question_id ๋ฅผ FK ๋ก ํ๋ ForeignKey ๊ด๊ณ ์์ฑ
private Question question;
}
- SpringBootTest
@Test
void ์ ์ฅ() {
Question q = questionRepository.findById(2).get();
// .
// 1๋ฒ ์ง๋ฌธ์ ๋ํ ๋ต๋ณ ๊ฐ์ฒด ์์ฑ ํ ์ ์ฅ
// .
// q ๋ค์ ๋ถ๋ฌ์ด
q = questionRepository.findById(2).get();
List<Answer> answerList = q.getAnswerList();
assertThat(answerList.size()).isEqualTo(1); // fetch ์ค์ ์ ๋ฐ๋ผ ๊ฒฐ๊ณผ ๋ฌ๋ผ์ง
}
โ OneToMany ๊ด๊ณ์์ Fetch.LAZY ์ผ ๋ (default)
public class Question {
// .
// .
@OneToMany (mappedBy = "question", cascade = CascadeType.REMOVE)
private List<Answer> answerList;
}
failed to lazily initialize a collection of role: com.ay.study.qna.Question.answerList, could not initialize proxy - no Session
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ay.study.qna.Question.answerList, could not initialize proxy - no Session
# ์ฟผ๋ฆฌ๋ฌธ : Join ์์ด Question ๋ง ๊ฐ์ง๊ณ ์ด
SELECT
Q.id AS id1_1_0_,
Q.content AS content2_1_0_,
Q.create_date AS create_d3_1_0_,
Q.subject AS subject4_1_0_
FROM
question AS Q
WHERE
Q.id=1
โก๏ธ LAZY ์ค๋ฅ ๋ฐ์
โก OneToMany ๊ด๊ณ์์ Fehch.EAGER ์ผ ๋
public class Question {
// .
// .
@OneToMany (mappedBy = "question", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
private List<Answer> answerList;
}
# ์ฟผ๋ฆฌ๋ฌธ : Join ์ ํตํด question_id ๊ฐ ์ผ์นํ๋ answer ๋ ๊ฐ์ง๊ณ ์ด
SELECT
Q.id AS id1_1_0_,
Q.content AS content2_1_0_,
Q.create_date AS create_d3_1_0_,
Q.subject AS subject4_1_0_,
A.question_id AS question4_0_1_,
A.id AS id1_0_1_,
A.id AS id1_0_2_,
A.content AS content2_0_2_,
A.create_date AS create_d3_0_2_,
A.question_id AS question4_0_2_
FROM
question AS Q
LEFT OUTER JOIN
answer AS A
ON Q_.id=A.question_id
WHERE
Q.id=?
โก๏ธ ์ ์ ์๋
๐ Spring JPA Persistence Context (์์์ฑ ์ปจํ ์คํธ) ๊ด๋ จ ๋ด์ฉ
โข (๋ฒ์ธ) Spring Boot JPA Test ์์ OneToMany ์ Fetch ์ค์ ์ Lazy ๋ก ์ ์งํ ์ํ์์ Lazy ์ค๋ฅ๋ฅผ ๋ฐ์์ํค์ง ์์ผ๋ ค๋ฉด?
- ํด๋น ๋ด์ฉ์ ๊ณต๋ถํ๊ธฐ ์ ์ค์ค๋ก ๊ณต๋ถํ ๋ LAZY ์ค๋ฅ๋ฅผ ํผํ๊ธฐ ์ํด์ Test ์ฝ๋์ @Transactional ์ ์ถ๊ฐํ์ฌ ์๋์์ผฐ๋ค. ๊ทธ ๊ฒฐ๊ณผ LAZY ์ค๋ฅ๋ ํผํ ์ ์์์ง๋ง, ์ ์ ์๋ ์ด์ ๋ก answerList ์ ๊ฐ์ด null ๋ก ๋์๋ค. ๊ณต๋ถํ๋ค๋ณด๋ ์ด๋ฌํ ๋ด์ฉ์ด ์์๋ค.
๊ฐ์ Transaction ์์๋ Entity ๋์ผ์ฑ์ด ๋ณด์ฅ๋๋ค. (๋์ผ ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.) โก๏ธ Spring JPA Persistence Context (1์ฐจ ์บ์ฌ)
์ ๋ด์ฉ์ JPA ์ ์์์ฑ ์ปจํ ์คํธ (์บ์ฌ) ์ ๊ฐ๋ ์ด๋ผ๊ณ ๋ณด๋ฉด๋๋ค.
์์ ์์ฑํ ํ ์คํธ ์ฝ๋์์ (1๏ธโฃ ๋ฒ์งธ ํธ์ถ) ๋งจ ์ฒ์ findById() ๋ฅผ ํตํด์ question ๊ฐ์ฒด๋ฅผ ๋ถ๋ฌ์ฌ ๋ DB์์ ํ์ ํ ๊ฐ์ ๊ฐ์ง๊ณ ์จ ๋ค ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋๊ณ ,
๋ต๋ณ ์ถ๊ฐ ํ (2๏ธโฃ ๋ฒ์งธ ํธ์ถ) ๋ค์ ํ ๋ฒ findById()๋ฅผ ํตํด question ๊ฐ์ฒด๋ฅผ ๋ถ๋ฌ์ฌ ๋๋ DB ์ ์ ์ ์์์ฑ ์ปจํ ์คํธ์์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ ์์ผ๋ฉด ๋ฐ๋ก ๊ฐ์ง๊ณ ์ค๊ธฐ ๋๋ฌธ์, Answer ๊ฐ์ฒด ์ถ๊ฐ ์ ์ํ์ธ, ์ฆ answerList๊ฐ null ์ธ ์ํ๋ฅผ ์ ์งํ ์ํ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
์ ๋ด์ฉ์ ํ ์คํธ ์ฝ๋์์ ์ง์ ๊ฐ์ฒด๋ฅผ ํธ์ถํด์ ํ์ธํด ๋ณผ ์ ์์๋ค.
@Test
@Transactional
@Rollback(false)
void ์ ์ฅ() {
Question q = questionRepository.findById(2).get();
System.out.println("์ฒซ๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : " + q);
// Answer ๊ฐ์ฒด ์ ์ฅ
// q ๋ค์ ๋ถ๋ฌ์ด
q = questionRepository.findById(2).get();
System.out.println("๋๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : " + q);
// (์๋ต)
}
Hibernate:
/* insert com.ay.study.qna.Answer
*/ insert
into
answer
(content, create_date, question_id)
values
(?, ?, ?)
์ฒซ๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : com.ay.study.qna.Question@64836643
Hibernate:
/* insert com.ay.study.qna.Answer
*/ insert
into
answer
(content, create_date, question_id)
values
(?, ?, ?)
๋๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : com.ay.study.qna.Question@64836643
๋ฐ๋ผ์ Fetch ์ค์ ์ ์ ์งํ๋ ค๋ฉด ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ด๊ธฐํ ํด์ฃผ์ด์ผํ๋ค.
@SpringBootTest
public class AnswerRepositoryTests {
// (์๋ต)
@Autowired
private EntityManager em; // EntityManager (์์์ฑ ์ปจํ
์คํธ ๊ฐ์ฒด ์์ฑ)
// (์๋ต)
@Test
@Transactional
@Rollback(false)
void ์ ์ฅ() {
Question q = questionRepository.findById(2).get();
System.out.println("์ฒซ๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : " + q);
// (์๋ต)
em.clear(); // ์์์ฑ ์ปจํ
์คํธ ์ด๊ธฐํ
// q ๋ค์ ๋ถ๋ฌ์ด
q = questionRepository.findById(2).get();
System.out.println("๋๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : " + q);
// (์๋ต)
}
}
์ฒซ๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : com.ay.study.qna.Question@3da6950f
๋๋ฒ์งธ ํธ์ถ question ๊ฐ์ฒด : com.ay.study.qna.Question@2eb31735
๊ทธ ๊ฒฐ๊ณผ ๊ฐ์ฒด๊ฐ ๋ค๋ฅด๊ฒ ํธ์ถ๋๊ณ , ํ ์คํธ๋ ์ ์ํต๊ณผ ํ๋ค.