2021. 10. 5. 22:27ใBack-End ์์ ์ค/Spring Framework
๐ @ManyToOne
์ด๊ฒ์ ํ ์ด๋ธ ๊ฐ์ ์ฐ๊ด๊ด๊ณ๊ฐ ์์ ๋, ์ฌ์ฉํ๋ ๊ฒ์ด์์. RDBMS์์๋ FK๋ฅผ ํตํด ๋ค๋ฅธ Table์ ์ฐธ์กฐํ ์ ์๋ ๊ฒ์ด์์. ์ด ๋, N:1, 1:N, N:M ๋ฑ์ ๊ด๊ณ๊ฐ ํ์ฑ์ด ๋๋๋ฐ, ์๋ฅผ ๋ค์ด Member (ํ์) Table๊ณผ Board (๊ฒ์ํ) Table์ด ์์ ๋, ํ ๋ช ์ ํ์์ ์ฌ๋ฌ๊ฐ์ ๊ฒ์๊ธ์ ๋จ๊ธธ ์ ์๋ ๊ฒ์ด์์.
๊ทธ๋ฐ๋ฐ, ์ฌ๊ธฐ์ ์ฃผ์ํด์ผ ํ ์ ์ @ManyToOne๋ ์๊ณ , @OneToMany๋ ์๋ ๊ฒ์ธ๋ฐ, ์ด๋ป๊ฒ ๊ตฌ๋ถํด์ ์ฌ์ฉํด์ผ ํ ๊น์?
๋ฐ๋ก ์ฐธ์กฐ๋ฅผ ํ Table ๊ธฐ์ค์ผ๋ก ์๊ฐ์ ํ๋ฉด ๋๋ต๋๋ค! Board Table์ด Member Table์ ์ฐธ์กฐํ ๊ฒ์ด๊ณ , Board Table์ด N์ด๊ธฐ ๋๋ฌธ์ Board Entity์์ @ManyToOne์ ์ฌ์ฉํ๋ฉด ๋๋ ๊ฒ์ด์์.
์์ Code๋ SystemUseManual์ด๋ผ๋ ๊ฒ์ํ๊ณผ Member Table์ ์ฐ๊ด ๊ด๊ณ ์ง์ ์ ํด ์ค ๊ฒ์ด์์.
์์ฑ์๋ก ์ฌ์ฉํ๊ธฐ ์ํด ๋ณ์๋ช ์ writer๋ผ๊ณ ํ๋ต๋๋ค!
์ฃผ๋ํ๋์ ํ์ฌ ํด๋น ๊ฒ์ํ์ ๋๊ธ ๊ธฐ๋ฅ๋ ๋ฃ๊ธฐ ์ํด ๋ฐ๋ก Entity๋ฅผ ๋ถ๋ฆฌํ ๊ฒ์ด์์.
๊ทผ๋ฐ ์ฌ๊ธฐ์ ์ ๊ฐ ์ ๋ชป ํ๋จํ ๊ฒ์ด ์๋ ๊ฒ์ด์์. ์์ Code๋ฅผ ๋ณด๋ฉด ๊ฒ์ํ๊ณผ์ ์ฐ๊ด ๊ด๊ณ๋ฅผ ์ํด @ManyToOne์ ์ฐ๊ณ , ๋๊ธ ์์ฑ์๊ฐ ํ์ํ๋๊น ๋น์ฐํ Member Table๊ณผ ๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์ด์ค์ผ ํ๋์ง ์ ๊ฒ์ด์์.
ํ์ง๋ง ์ด๊ฑด ์์ฒญ๋ ์ฐฉ๊ฐ์ด๊ณ , ์ค์์๋ต๋๋ค!
์์ left outer join์ผ๋ก ์ฌ๋ฌ Entity์ ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋งบ์ด์ Data๋ฅผ ๊ฐ๊ณ ์ค๋๋ฐ, ๋ณด์๋ค ์ํผ Member Entity๋ฅผ ๋ ๋ฒ์ด๋ Joinํ๊ณ ์๋ ๊ฒ์ด์์!
์์ ๊ฐ์ด Member์ ๋ํ ์ฐ๊ด ๊ด๊ณ๋ฅผ ์์ค ๋ค ๋ค์ Test๋ฅผ ์งํ ํด ๋ณผ ๊ฒ์ด์์.
์ด๋ฒ์๋ ์ ์์ ์ผ๋ก ๋ฑ! ํ๋ฒ๋ง Member Entity๋ก join์ ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ ๊ฒ์ด์์.
ํ.์ง.๋ง ์์์ ๋ณด๋ ๋ฐ์ ๊ฐ์ด SQL ๋ฌธ์ ๋ณด๋ฉด Comment Table, UseManual Table, Member Table๊น์ง ๋ชจ๋ Join์ผ๋ก ์ฒ๋ฆฌํ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์. Comment๋ฅผ ๊ฐ์ ธ์ฌ ๋, ๋งค๋ฒ ๊ฒ์ํ(UseManual)๊ณผ Member๊น์ง Joinํด์ ๊ฐ์ ธ์ฌ ํ์๊ฐ ๋ง์ง๋ ์๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ด ์ฌ๋ฌ Table์ Join์ผ๋ก ์ฒ๋ฆฌ๋๋ ์ํฉ์ ์ข์ง ์์ ๊ฒ์ด์์.
๐ fetch๋ Lazy Loading์ ์ฌ์ฉํ์!
์์ Query ์คํ ๊ฒฐ๊ณผ์ ๊ฐ์ด ํน์ Entity๋ฅผ ์กฐํํ ๋, ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง ๋ชจ๋ Entity๋ฅผ ๊ฐ์ด Lodingํ๋ ๊ฒ์ 'Eager Loding'์ด๋ผ๊ณ ํ๋ ๊ฒ์ด์์. 'Eager'๋ '์ด๋ ฌํ, ์ ๊ทน์ ์ธ'์ด๋ผ๋ ๋ป์ ๊ฐ๊ณ ์๊ณ , ์ผ๋ฐ์ ์ผ๋ก '์ฆ์ ๋ก๋ฉ'์ด๋ผ๊ณ ํํํ๋ ๊ฒ์ด์์.
'์ฆ์ ๋ก๋ฉ'์ ํ ๋ฒ์ ์ฐ๊ด ๊ด๊ณ๊ฐ ์๋ ๋ชจ๋ Entity๋ฅผ ๊ฐ์ ธ์จ๋ค๋ ์ฅ์ ์ด ์์ผ๋, ์ฌ๋ฌ ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋งบ๊ณ ์๊ฑฐ๋, ์ฐ๊ด ๊ด๊ณ๊ฐ ๋ณต์กํ ์๋ก Join์ผ๋ก ์ธํ ์ฑ๋ฅ ์ ํ๋ฅผ ํผํ ์ ์๋ ๊ฒ์ด์์.JPA์์ ์ฐ๊ด ๊ด๊ณ์ Data๋ฅผ ์ด๋ป๊ฒ ๊ฐ์ ธ์ฌ ๊ฒ์ธ๊ฐ๋ฅผ fetch(ํจ์น)๋ผ๊ณ ํ๋๋ฐ, ์ฐ๊ด ๊ด๊ณ Annotation์ ์์ฑ์ผ๋ก 'fetch' Mode๋ฅผ ์ง์ ํ๋ต๋๋ค!
์ฆ์ ๋ก๋ฉ์ ๋ถ ํ์ํ Join๊น์ง ์ฒ๋ฆฌํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ ์ฌ์ฉํ์ง ์๊ณ , ๊ทธ์ ๋ฐ๋๋๋ 'Lazy Loding'์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ข์ ๊ฒ์ด์์. 'Lazy Loding'์ '์ง์ฐ ๋ก๋ฉ, ๊ฒ์ด๋ฅธ ๋ก๋ฉ'์ด๋ผ๊ณ ๋ถ๋ฅธ๋ต๋๋ค!
๊ทธ๋ฌ๋ฉด ๊ฒ์ํ(UseManul)์ ํ๋ฒ ๊ณ ์ณ ๋ณด๋๋ก ํ ๊ฒ์ด์์.
UseManual Entity Class์์ ์์ ๋ ๋ถ๋ถ์ @ManyToOne์ fetch ์์ฑ์ ๋ช ์ํ๊ณ , FetchType.LAZY๋ผ๋ ์ง์ฐ ๋ก๋ฉ์ ์ ์ฉํ ๋ถ๋ถ์ธ ๊ฒ์ด์์. ๊ทธ๋ผ ๋ค์ Test๋ฅผ ๋๋ ค ๋ณด๋๋ก ํ ๊ฒ์ด์์!
์! ๋ญ๊ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒ์ด์์! ๋ฐ์ํ Exception Message๋ ์๋์ ๊ฐ์ ๊ฒ์ด์์.
์ด ๋ง์ Data Base์ ์ถ๊ฐ์ ์ธ ์ฐ๊ฒฐ์ด ํ์ํ๋ค๋ ๊ฒ์ด์์.
์ง์ฐ ๋ก๋ฉ ๋ฐฉ์์ผ๋ก ๋ก๋ฉํ๊ธฐ ๋๋ฌธ์ UseManual Table๋ง ๊ฐ์ ธ์์ System.out.println()์ ํ๋ ๊ฒ์ ๋ฌธ์ ๊ฐ ์์ง๋ง,
์ฌ๊ธฐ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด์์. manual.getWriter()๋ member Table์ ๋ก๋ฉํด์ผ ํ๋๋ฐ, ์ด๋ฏธ Data Base์ ์ฐ๊ฒฐ์ด ๋๋ ์ํ์ด๊ธฐ ๋๋ฌธ์ Exception์ด ํฐ์ง๋ ๊ฒ์ด์์.
'no Session'์ด๋ผ๋ ๋ฉ์์ง๋ ์ด๋ฐ ๊ฒฝ์ฐ ๋ฐ์ํ๋ต๋๋ค! ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ค์ ํ๋ฒ Data Base์ ์ฐ๊ฒฐ์ด ํ์ํ๋ฐ, @Transactional์ด ๋ฐ๋ก ์ด๋ฌํ ์ฒ๋ฆฌ์ ๋์์ ์ฃผ๋ ๊ฒ์ด์์. Method ์ ์ธ๋ถ์ ์ด Annotation์ ๋ฃ์ด ๋ณด๋๋ก ํ ๊ฒ์!
@Transactional ์ด ์น๊ตฌ๋ ํด๋น Method๋ฅผ ํ๋์ 'ํธ๋์ญ์ '์ผ๋ก ์ฒ๋ฆฌํ๋ผ๋ ์๋ฏธ์ธ ๊ฒ์ด์์. ํธ๋์ญ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ์์ฑ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ๋์ํ์ง๋ง, ๊ธฐ๋ณธ์ ์ผ๋ก๋ ํ์ํ ๋ ๋ค์ Data Base์ ์ฐ๊ฒฐ์ด ์์ฑ๋๋ต๋๋ค!
๐ก ์ฐธ๊ณ :
Transaction์ด๋?
Hibernate:
select
systemusem0_.no as no1_1_0_,
systemusem0_.moddate as moddate2_1_0_,
systemusem0_.regdate as regdate3_1_0_,
systemusem0_.content as content4_1_0_,
systemusem0_.title as title5_1_0_,
systemusem0_.writer_id as writer_i6_1_0_
from
system_use_manual systemusem0_
where
systemusem0_.no=?
com.hongga.junyharang.domain.entity.manual.SystemUseManual@202b5293
Hibernate:
select
member0_.id as id1_0_0_,
member0_.moddate as moddate2_0_0_,
member0_.regdate as regdate3_0_0_,
member0_.email as email4_0_0_,
member0_.grade as grade5_0_0_,
member0_.name as name6_0_0_,
member0_.password as password7_0_0_,
member0_.phone as phone8_0_0_
from
member member0_
where
member0_.id=?
com.hongga.junyharang.domain.entity.member.Member@7137cd14
2021-10-05 18:41:40.137 INFO 17188 --- [ Test worker] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@2ce86164 testClass = SystemUseManualRepositoryTest, testInstance = com.hongga.junyharang.repository.manual.SystemUseManualRepositoryTest@9ba167e, testMethod = ๊ฒ์๊ธ_์กฐํ@SystemUseManualRepositoryTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@5e8f9e2d testClass = SystemUseManualRepositoryTest, locations = '{}', classes = '{class com.hongga.junyharang.JunyharangApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@4c51cf28, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@66ac5762, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@517d4a0d, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@1941a8ff, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@6aa3a905, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@1e683a3e], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]
Test ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ฒ์์๋ SystemUseManual Table๋ง ๋ก๋ฉํด์ ์ฒ๋ฆฌํ์์ผ๋, SystemUseManual.getWriter()๋ฅผ ํ๊ธฐ ์ํด member Table์ ๋ก๋ฉํ๋ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์. ์ง์ฐ ๋ก๋ฉ์ ์ฌ์ฉํ์ง ์์์ ๊ฒฝ์ฐ ์๋์ SystemUseManual Table๊ณผ Member Table์ด ์กฐ์ธ์ผ๋ก ์ฒ๋ฆฌ๋ ๊ฒ๊ณผ๋ ์ฐจ์ด๊ฐ ์๋ ๊ฒ์ ์ ์ ์๋ ๊ฒ์ด์์.
๐ ์ง์ฐ ๋ก๋ฉ ( lazy loding )์ ์ฅ / ๋จ์
์ง์ฐ ๋ก๋ฉ์ ์กฐ์ธ์ ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋จ์ํ๊ฒ ํ๋์ ํ ์ด๋ธ์ ์ด์ฉํ๋ ๊ฒฝ์ฐ์๋ ๋น ๋ฅธ ์๋์ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ ๊ฒ์ด์์. ํ์ง๋ง, ์์ ๊ฐ์ด ํ์ํ ์๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์คํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฐ๊ด ๊ด๊ณ๊ฐ ๋ณต์กํ ๊ฒฝ์ฐ ์ฌ๋ฌ ๋ฒ์ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋ค๋ ๋จ์ ์ด ์๋ ๊ฒ์ด์์.
๋ฐ๋ผ์ ๋ณดํธ์ ์ธ ์ฝ๋ฉ ๊ฐ์ด๋๋ '์ง์ฐ ๋ก๋ฉ์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๊ณ , ์ํฉ์ ๋ง๊ฒ ํ์ํ ๋ฐฉ๋ฒ์ ์ฐพ๋๋ค' ์ธ ๊ฒ์ด์์.
'Back-End ์์ ์ค > Spring Framework' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] Component Scan And Auto wired Start (0) | 2021.10.06 |
---|---|
[JPQL] left ( outer ) join (0) | 2021.10.05 |
[Spring] ์ฑ๊ธํค ์ปจํ ์ด๋ (0) | 2021.10.05 |
[Spring] ์คํ๋ง ์ปจํ ์ด๋ ์์ฑ (0) | 2021.10.03 |
[Spring] Ioc, DI Container (0) | 2021.10.01 |