Jdbi: @CreateSqlObject๋ฅผ ๋œ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2018๋…„ 02์›” 01์ผ  ยท  20์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: jdbi/jdbi

๋ฌธ์ œ
JDBI ๊ณต์‹ ๋ฌธ์„œ๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด @CreateSqlObject ์ฃผ์„์ด ์ด์งˆ์ ์ธ DAO์— ํŠธ๋žœ์žญ์…˜ ์ง€์›์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋ผ๊ณ  ๋ฏฟ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

http://jdbi.org/#__createsqlobject

์„ ํ˜ธํ•˜๋Š” jdbi.onDemand ์ƒ์„ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ ์ƒํƒœ ์˜ค๋ฅ˜๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ์‹ค์ œ ๋™์ž‘์— ๋Œ€ํ•ด ์•ฝ๊ฐ„ ์˜คํ•ด์˜ ์†Œ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ํ˜ผ๋ž€์„ ์„ค๋ช…ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฉ”์‹œ์ง€๊ฐ€ ํฌ๋Ÿผ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์š”๊ตฌ
์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ์ƒ์˜ ์†”๋ฃจ์…˜์ด ๋ฌด์—‡์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒ๊ฐ๋‚˜๋Š” ๋ช‡ ๊ฐ€์ง€:

  • ์ฒœ์นญ
  • ๋‹จ์ ์— ๋Œ€ํ•œ ๋” ๋‚˜์€ ๋ฌธ์„œํ™”
  • ์—ฌ๋Ÿฌ DAO์—์„œ ์ฟผ๋ฆฌ๋ฅผ ๋ถ„ํ• ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด์ง€๋งŒ ๋…ผ๋ฆฌ์  ํŠธ๋žœ์žญ์…˜ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ํ•จ๊ป˜ ๋ฌถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ฝ๊ธฐ ์ „์šฉ/์“ฐ๊ธฐ ํŠธ๋žœ์žญ์…˜์˜ ํ˜ผํ•ฉ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
cleanup improvement

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด์— ๋Œ€ํ•ด ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋Œ“๊ธ€์„ ๋‹ฌ์•„ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ๋กœ๋“œ๋งต์— ์ด๊ฒƒ์— ๋„์›€์ด ๋  ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ถ„๋ช…ํžˆ ํ˜ผ๋ž€์˜ ์›์ธ์ด๋ฉฐ ์šฐ๋ฆฌ๊ฐ€ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ง€๋‚œ๋ฒˆ์— ์šฐ๋ฆฌ๊ฐ€ ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒˆ์—๋Š” ๊ทธ๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ฅผ ์ •๋ง๋กœ ์›ํ•ฉ๋‹ˆ๋‹ค. :)

( @svlada ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” @Transactional ์„ ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค)

์˜ˆ, ํ•˜์ง€๋งŒ ๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ํ•œ, ์ด๋Š” ๋ชจ๋‘ DI ํ”„๋ ˆ์ž„์›Œํฌ(์˜ˆ: Spring)์˜ AOP ํ›„ํฌ๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. JDBI๊ฐ€ ๋ชจ๋“  ์„œ๋น„์Šค ๊ฐœ์ฒด๋ฅผ "๋ž˜ํ•‘"ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์ƒ์„ฑํ•˜์ง€ ์•Š์€ ๊ฐœ์ฒด์— ๋Œ€ํ•ด AOP์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•  ๊ธฐํšŒ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด์ „ cglib ๊ตฌํ˜„์กฐ์ฐจ๋„ daos ์ž์ฒด์—์„œ @Transactional ๋งŒ ์•Œ ์ˆ˜ ์žˆ์—ˆ๊ณ  ๋ณ„๋„์˜ ์„œ๋น„์Šค ํด๋ž˜์Šค์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„์›€์ด ๋œ๋‹ค๋ฉด ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ ํŠธ๋žœ์žญ์…˜์„ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ๋ฅผ ๋“ค์–ด Spring ๋ฐ/๋˜๋Š” Guice AOP ๋ฐ”์ธ๋”ฉ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ core ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ spring ํ™•์žฅ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ•ต์‹ฌ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋›ฐ์–ด๋„˜์„ ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š์ง€๋งŒ ๊ธฐ์—ฌ๋Š” ํฌํ•จ์„ ์œ„ํ•ด ์ง„์ง€ํ•˜๊ฒŒ ๊ณ ๋ ค๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. "๋” ๊น”๋”ํ•œ" ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

์šฐ๋ฆฌ๋Š” ์ฃผ๋กœ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด cglib ์—์„œ Proxy ๋กœ ์ „ํ™˜ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. Proxy ๋Š” ์ง€์›๋˜๋Š” jdk API์ธ ๋ฐ˜๋ฉด cglib (๋˜๋Š” ๋ณด๋‹ค ๊ตฌ์ฒด์ ์œผ๋กœ asm ) ๋ชจ๋“  ์ฃผ์š” ๋ฆด๋ฆฌ์Šค(8, 9, 11, ...์— ์ค‘๋‹จ๋จ)์™€ ํ•จ๊ป˜ ์ค‘๋‹จ๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์œผ๋ฉฐ ์ด๋Š” ์œ ์ง€ ๊ด€๋ฆฌ์— ํฐ ๊ณจ์นซ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  20 ๋Œ“๊ธ€

์‹ ๊ณ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๊ธฐ์ˆ ์ ์œผ๋กœ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์„ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ธฐ์กด ๋™์ž‘์ด 3.x ๋ฆด๋ฆฌ์Šค ์ฃผ๊ธฐ์˜ ์ดˆ๊ธฐ์— ๊ธฐ์ˆ ์ ์œผ๋กœ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋งŒ๋“ค ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์ข‹์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ๋™์ž‘์— ์˜์กดํ•˜๊ฑฐ๋‚˜ ์ž ์žฌ์ ์œผ๋กœ ์ž‘์€ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์—ฌ๊ธฐ์— ์ œ๊ณตํ•˜๋Š” ๋ฐ ๋™์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ด ๋ฌธ์ œ์— ํ”Œ๋ž˜๊ทธ๋ฅผ ์ง€์ •ํ•˜์‹ญ์‹œ์˜ค.

@CreateSqlObject ๊ฐ€ ์˜จ๋””๋งจ๋“œ์—์„œ ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” _์ด์œ _์— ๋Œ€ํ•œ ์ปจํ…์ŠคํŠธ:

  • ์ฃผ๋ฌธํ˜•์€ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋˜๋Š” ํ•ต์‹ฌ ์ˆ˜์ค€์˜ ์ถ”์ƒํ™”์ž…๋‹ˆ๋‹ค. ์š”์ฒญ ์‹œ ํ”„๋ก์‹œ์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์‹ค์ œ SQL ๊ฐœ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ์‹ค์ œ SQL ๊ฐœ์ฒด์— ์œ„์ž„๋ฉ๋‹ˆ๋‹ค. ๋Œ€๋ฆฌ์ž ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ๋ฐ˜ํ™˜๋œ ํ›„ ํ•ด๋‹น ์‹ค์ œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ง€์›ํ•˜๋Š” ํ•ธ๋“ค์ด ๋‹ซํž™๋‹ˆ๋‹ค.
  • @CreateSqlObject ๋Š” handle.attach(sqlObjectType) ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋˜๋ฉฐ ์›๋ž˜ SQL ๊ฐœ์ฒด์˜ ์ง€์› ํ•ธ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ƒ์„ฑ๋œ SQL ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์ง€์› ํ•ธ๋“ค์€ SQL ๊ฐœ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ธฐ ์ „์— ๋‹ซํž™๋‹ˆ๋‹ค.

์œ„์˜ ์–ด๋Š ๊ฒƒ๋„ ํ™•์ •๋œ ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ ํ˜„์žฌ ๊ตฌํ˜„๋œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ˜ธํ™˜์„ฑ์„ ๊นจ์•ผ ํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค... onDemand ๋ฐ CreateSqlObject์˜ ๋ฌธ์ œ๋Š” ์ •ํ™•ํžˆ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๊ณ  @qualidafial ์˜ ์„ค๋ช…์— ๋Œ€ํ•œ ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋‚ด ๋งˆ์Œ์„ ๊ธฐ์šธ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค ...

image

fooProxy.usecase ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์ด ํ™•๋ณด๋ฉ๋‹ˆ๋‹ค. Foo.usecase ๋Š” ํ˜„์žฌ( usecase ์˜) ํ•ธ๋“ค์— ์—ฐ๊ฒฐํ•œ ํ›„ ์ƒˆ Bar ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” createSqlObject ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. usecase ๊ฐ€ ๋ฐ˜ํ™˜๋˜๋ฉด usecase ์˜ ํ•ธ๋“ค์ด ๋‹ซํž™๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ Bar ์™€ ๋น„๋™๊ธฐ์‹์œผ๋กœ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š” ํ•œ ์–ด๋–ป๊ฒŒ bar ์˜ ํ•ธ๋“ค์ด ๋„ˆ๋ฌด ์ผ์ฐ ๋งŒ๋ฃŒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? bar ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ์™€ ์‚ฌ์šฉ์€ ํ•ธ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Foo.usecase ์˜ ๋ณธ๋ฌธ์œผ๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค.

JDBI ๋‚ด๋ถ€์— ๋Œ€ํ•ด ๋งํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ํ”„๋กœ๋•์…˜์—์„œ ๋ณธ ๋™์ž‘์— ๋Œ€ํ•ด์„œ๋Š” ์–ธ๊ธ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ์šฐ๋ฆฌ์˜ ๋‚ฎ์€ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ดœ์ฐฎ์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ”„๋กœ๋•์…˜์˜ ๋กœ๋“œ๊ฐ€ ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…ธ๋“œ์— ๋Œ€ํ•ด SQL ๋ฌธ์ด ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ„์† ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฝ๊ธฐ ์ „์šฉ ์„ ํƒ์€ ๋งˆ์Šคํ„ฐ ๋…ธ๋“œ์— ๋„๋‹ฌํ•˜๊ณ  ์‚ฝ์ž…์€ ์ฝ๊ธฐ ์ „์šฉ ๋ณต์ œ๋ณธ์— ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž‘์—… ๋„์ค‘์— ์—ฐ๊ฒฐ ๋‹ซํž˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ณธ์งˆ์ ์œผ๋กœ @CreateSqlObject ๊ฐ€ ์Šค๋ ˆ๋“œ ์•ˆ์ „ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฝ๊ธฐ ์ „์šฉ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๊ฒฝ์Ÿ ์š”์ฒญ์— ์˜ํ•ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ "ํ•ด๊ฒฐ"ํ•˜๊ธฐ ์œ„ํ•ด @CreateSqlObject ์˜ ๋ชจ๋“  ์‚ฌ์šฉ์„ ์ œ๊ฑฐํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋๋ƒˆ์Šต๋‹ˆ๋‹ค.

  • class FooDao
  • class BarDao
  • class CombinedDao extends FooDao, BarDao

๊ทธ๋Ÿฐ ๋‹ค์Œ ์šฐ๋ฆฌ๋Š” jdbi.onDemand(CombinedDao) ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด๋ฅผ ํ†ตํ•œ ์•ก์„ธ์Šค๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๊ทธ ํŒจํ„ด์œผ๋กœ ์ „ํ™˜ํ•˜๋ฉด ์˜ˆ์˜์ง€๋Š” ์•Š์ง€๋งŒ ์•ž์„œ ์–ธ๊ธ‰ํ•œ ํ”„๋กœ๋•์…˜ ์˜ค๋ฅ˜๊ฐ€ ๋ชจ๋‘ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ •๋ณด๋ฅผ ์œ„ํ•ด, ์ œ ๋ชจ๋“  ์ฝ”๋“œ๊ฐ€ ํ˜„์žฌ ์ถ”์ƒ ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ onDemand๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— JDBI 2๋กœ ๋Œ์•„๊ฐˆ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ œ๊ฐ€ ๋งŒ์กฑํ•  ๋ฐฉ์‹์œผ๋กœ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!

์ €๋Š” ์ˆœ์ˆ˜ SQL์ธ DAO ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด CreateSqlObject๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ฃผ์„์ด ๋‹ฌ๋ฆฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋…ผ๋ฆฌ๋ฅผ ํฌํ•จํ•˜์ง€๋งŒ SQL์€ ํฌํ•จํ•˜์ง€ ์•Š๋Š” ์ถ”์ƒ ๊ตฌํ˜„ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํ™”๋œ ์˜ˆ:

์ƒํ˜ธ ์ž‘์šฉ

public interface AccountService {
    void addAccount(Account account, User user);
}  

๊ตฌํ˜„

public abstract class AccountServiceJdbi implements AccountService {

    <strong i="11">@Override</strong>  
    <strong i="12">@Transaction</strong>  
    public final void addAccount(@BindBean() Account account, User user) {
        long accountId =  accountDao().insertAccount(account);
        accountDao().linkAccountToOwner(accountId, user.getId());
    }

    <strong i="13">@CreateSqlObject</strong>
    abstract AccountDao accountDao();
}

(๋‹น์‹ ์€ Dao๋ฅผ ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค)

์ด๊ฒƒ์€ ์—ฌ๋Ÿฌ DAO ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•œ ํŠธ๋žœ์žญ์…˜์„ ํ—ˆ์šฉํ•˜๋ฉด์„œ ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค๋ฅผ ์•„์ฃผ ํ›Œ๋ฅญํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” DAO ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ์ž‘์„ฑํ•˜๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

JDBI 3์—์„œ ๋น„์Šทํ•œ ์ž‘์—…์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋‚ด ์„œ๋น„์Šค ํด๋ž˜์Šค์˜ ๊ตฌํ˜„์ด ๋…ผ๋ฆฌ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ๋Š” ์ตœ์ข…์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜์ง€ ์•Š๊ณ  ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํ†ต์ œ๋ ฅ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

์ตœ์ข… ํŠธ๋žœ์žญ์…˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋„๋ก JDBI 3์—์„œ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ธํ„ฐํŽ˜์ด์Šค ๋ฉ”์†Œ๋“œ๋ฅผ final๋กœ ์ •์˜ํ•  ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ @SqlQuery , @SqlUpdate ๋“ฑ๊ณผ ๋™๋“ฑํ•œ ์ž์ฒด SQL ๋ฉ”์†Œ๋“œ ์ฃผ์„์„ ์ •์˜ํ•˜๊ณ  ํ•ด๋‹น ์ฃผ์„์œผ๋กœ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ •์  ๊ตฌํ˜„์„ โ€‹โ€‹์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ @SqlQuery , @SqlUpdate ๋“ฑ๊ณผ ๋™๋“ฑํ•œ ์ž์ฒด SQL ๋ฉ”์†Œ๋“œ ์ฃผ์„์„ ์ •์˜ํ•˜๊ณ  ํ•ด๋‹น ์ฃผ์„์œผ๋กœ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ •์  ๊ตฌํ˜„์„ โ€‹โ€‹์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ต๋ณ€์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ DAO์— ์ฟผ๋ฆฌ๋ฅผ ํฌํ•จํ•˜๋˜ ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์—ฌ๋Ÿฌ DAO์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๊ฐœ์ธ์ ์œผ๋กœ ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

interface Dao1 {
  @SqlQuery("...")
  void query1();
}

interface Dao2 {
  @SqlQuery("...")
  void query2();
}

interface JdbiServiceImpl extends Service {
  <strong i="8">@CreateSqlObject</strong>
  Dao1 dao1();
  <strong i="9">@CreateSqlObject</strong>
  Dao2 dao2();

  <strong i="10">@Transaction</strong>
  <strong i="11">@Override</strong>
  void businessCase() {
    dao1().query1();
    dao2().query2();
  }
}

Service service = handle.attach(JdbiServiceImpl.class);
service.businessCase();

์ด๋Ÿฐ ์‹์œผ๋กœ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. @CreateSqlObject ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ getter/setter์— ์˜ํ•œ ์Šคํ”„๋ง์˜ ์ข…์†์„ฑ ์ฃผ์ž…๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด ์Šคํ”„๋ง ์ปจํ…์ŠคํŠธ์— onDemand ์ธ์Šคํ„ด์Šค๋ฅผ bean์œผ๋กœ ๋‘์–ด ์ผ๋ฐ˜ ์„œ๋น„์Šค์™€ ๋˜‘๊ฐ™์ด ์ž‘๋™ํ•˜๋ฏ€๋กœ ํ˜ธ์ถœ์ž๋Š” jdbi ๋˜๋Š” ๊ตฌํ˜„ ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•ด ์•Œ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

image

๋‹น์‹ ์ด ๋ณด๋Š” ๋ฐ˜ํŒจํ„ด ๋ชจ์–‘์˜ StockReductionCase๋Š” CreateSqlObject๋ฅผ ์‚ฌ์šฉํ•œ ์ค‘์ฒฉ๋œ jdbi "์ข…์†์„ฑ ์ฃผ์ž…"์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์„œ๋น„์Šค ๊ตฌํ˜„๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‚ด๋ถ€์— ์ž์ฒด ์ข…์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ทธ ์ž์ฒด๋กœ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ์„œ๋น„์Šค(์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ตœ์ƒ์œ„ ๋…ผ๋ฆฌ) ๋‚ด๋ถ€์— Cases(์—ฌ๋Ÿฌ ์œ„์น˜์— ํ•„์š”)์™€ ์ฟผ๋ฆฌ๋ฅผ ๋‘˜ ์ค‘ ํ•˜๋‚˜์— ๋„ฃ์Œ์œผ๋กœ์จ ์ˆœํ™˜ ์ข…์†์„ฑ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด Service ๋Œ€์‹  Case๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

image

@CreateSqlObject , ํŠนํžˆ onDemand() ์™€ ๊ฒฐํ•ฉํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง€์ •ํ•˜๋Š” ๋ฐ ์„ฑ๊ณตํ–ˆ๋‹ค๋Š” ํ˜ผํ•ฉ ๋ณด๊ณ ์„œ๋ฅผ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ์—ฌ๋Ÿฌ SQL ๊ฐœ์ฒด๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์€ Handle.inTransaction() ๋˜๋Š” Jdbi.inTransaction() ๋ฅผ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ๋‚ด์—์„œ Handle.attach() ๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๋ชจ๋“  DAO๋Š” ํ•ธ๋“ค ํŠธ๋žœ์žญ์…˜์˜ ์ผ๋ถ€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

jdbi.useTransaction(handle -> {
  Dao1 dao1 = handle.attach(Dao1.class);
  Dao2 dao2 = handle.attach(Dao2.class);

  dao1.doStuff();
  dao2.doMoreStuff();
});

๋‹ต๋ณ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค
@qualidafial ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ๊ฐ€์•ผ ํ•  ๊ธธ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์„œ๋น„์Šค ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. Daos ์ž์ฒด๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๋ฏ€๋กœ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ๋ชจ์˜ Daos๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@RealMarnes ๋„ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์‹œ๋„ํ•œ ๊ฒƒ๊ณผ ๋น„์Šทํ•ด ๋ณด์ด์ง€๋งŒ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@qualidafial ์—ฌ๋Ÿฌ dao ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ์— jdbi์˜ @Transaction ์ฃผ์„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ์„ ํ™•์ธํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์ด ๊ฐ€์ •์ด ๋งž๋‹ค๋ฉด ๊ณต์‹ ๋ฌธ์„œ์˜ ์ผ๋ถ€๋กœ ์ œ๋Œ€๋กœ ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์€ ์ด ๋™์ž‘์€ ๋งค์šฐ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ Spring ์Šคํƒ์— ๋Œ€ํ•œ ๊ฒฝํ—˜์ด ์žˆ๊ณ  @Transactional ์ฃผ์„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ DAO์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ๋งค์šฐ ํ‘œ์ค€์ ์ธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

@svlada @Transaction ์ฃผ์„ _only_๋Š” SQL ๊ฐœ์ฒด์˜ ๋ฉ”์„œ๋“œ์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. "์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ"๋ผ๊ณ  ๋งํ•  ๋•Œ Jdbi์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ์ผ๋ถ€ ๊ฐ์ฒด(์˜ˆ: ์ฃผ์ž…๋œ ํด๋ž˜์Šค)์— ์ฃผ์„์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ธ์ƒ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์˜ ์˜ˆ:

<strong i="9">@Test</strong>
public void testInsertAndFind() {
    Foo foo = handle.attach(Foo.class);
    Something s = foo.insertAndFind(1, "Stephane");
    assertThat(s).isEqualTo(new Something(1, "Stephane"));
}

<strong i="10">@Test</strong>
public void testTransactionPropagates() {
    Foo foo = dbRule.getJdbi().open().attach(Foo.class);

    assertThatExceptionOfType(Exception.class)
        .isThrownBy(() -> foo.insertAndFail(1, "Jeff"));

    Something n = foo.createBar().findById(1);
    assertThat(n).isNull();
}

public interface Foo {
    <strong i="11">@CreateSqlObject</strong>
    Bar createBar();

    @SqlUpdate("insert into something (id, name) values (:id, :name)")
    int insert(@Bind("id") int id, @Bind("name") String name);

    <strong i="12">@Transaction</strong>
    default Something insertAndFind(int id, String name) {
        insert(id, name);
        return createBar().findById(id);
    }

    <strong i="13">@Transaction</strong>
    default Something insertAndFail(int id, String name) {
        insert(id, name);
        return createBar().explode();
    }
}

public interface Bar {
    @SqlQuery("select id, name from something where id = :id")
    Something findById(@Bind("id") int id);

    default Something explode() {
        throw new RuntimeException();
    }
}

๋˜ํ•œ onDemand() + @CreateSqlObject ์— ๋Œ€ํ•ด ๋ช…ํ™•ํžˆ ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

  • @CreateSqlObject DAO๋Š” ์œ„์˜ ์˜ˆ์™€ ๊ฐ™์ด DAO๋ฅผ ๋งŒ๋“  DAO์˜ ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • fooDao.createBar().findById() ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์—ฐ๊ฒฐ์ด ๋‹ซํ˜”๋‹ค๋Š” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•ด ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋Œ“๊ธ€์„ ๋‹ฌ์•„ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ๋กœ๋“œ๋งต์— ์ด๊ฒƒ์— ๋„์›€์ด ๋  ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ์•„์ง๋„ ์ถ”์ƒ ํด๋ž˜์Šค์—์„œ CreateSqlObject๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ์ •๋ง ๊ทธ๋ฆฌ์›Œ์š”. ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์ œํ•œ์ ์ž…๋‹ˆ๋‹ค. ์ข…์ข… "์„œ๋น„์Šค" ์œ ํ˜•์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํŠธ๋žœ์žญ์…˜ ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€๋งŒ, ์ด๋Š” ๋‚ด ์„œ๋น„์Šค ํด๋ž˜์Šค๋„ ๊ธฐ๋ณธ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ, ๊ตฌ์ฒด์ ์ธ ์ตœ์ข… ๋ฉ”์†Œ๋“œ ๋“ฑ์˜ ๋ช…ํ™•์„ฑ์„ ์žƒ๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

@tamslinn ์ถ”์ƒ ํด๋ž˜์Šค ๋Œ€์‹  ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ๋ฌธ์ œ์— ๊ด€ํ•œ ํ•œ, ๊ฐ€๊นŒ์šด ์‹œ์ผ ๋‚ด์— ๊ทธ ๊ฒฐ์ •์—์„œ ๋Œ์•„์˜ค์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๋งํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Jdbi3๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ง€์›ํ•˜๋Š” jdk ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” cglib ๋˜๋Š” ์ด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์ผ๋ถ€์— ๊ตฌ์ถ•๋œ ๋ณ„๋„์˜ ๊ธฐ์—ฌ ๋ชจ๋“ˆ์ด ์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์ง€๊ธˆ ๋‹น์žฅ์€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

sqlobject ๊ณต๋ฆฌ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ•ญ์ƒ ์„œ๋น„์Šค๋ฅผ jdbi์— ์˜ํ•ด ํ–ฅ์ƒ๋˜์ง€ ์•Š์€ ์ผ๋ฐ˜ ํด๋ž˜์Šค๋กœ ๋ฆฌํŒฉํ† ๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋Œ€์‹  ์œ ์ฐฝํ•œ API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ฃผ์ž…๋œ Jdbi ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์˜ ํŠธ๋žœ์žญ์…˜ ์ง€์›, ์˜จ๋””๋งจ๋“œ ๋“ฑ ์‚ฌ์ด์˜ ํ–‰๋™์˜ ์›๋ž˜ ์ฃผ์ œ์— ๊ด€ํ•ด์„œ๋Š”, ๋น„๋ก ์šฐ๋ฆฌ๊ฐ€ ์•„์ง ์ •๋ง๋กœ ๊ตฌ์ฒด์ ์ธ ๊ณ„ํš์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ์ž‘์—…์— ์ ์  ๋” ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์— ๋„๋‹ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธํ•ด์ฃผ์…”์„œ ๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ก์‹œ์— ๋Œ€ํ•ด ์™„์ „ํžˆ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์ €์—๊ฒŒ ํŠน์ •ํ•œ ์ œํ•œ์€ JDBI ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘/์ข…๋ฃŒํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
( @svlada ๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ @Transactional ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค)
JDBI์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์ด ์ •๋ง ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ณ„์† ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์„œ๋น„์Šค ํด๋ž˜์Šค์— ๋งŒ์กฑํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์„ ์ƒ๊ฐํ•ด๋‚ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. :)

์ด์— ๋Œ€ํ•ด ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋Œ“๊ธ€์„ ๋‹ฌ์•„ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ๋กœ๋“œ๋งต์— ์ด๊ฒƒ์— ๋„์›€์ด ๋  ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ถ„๋ช…ํžˆ ํ˜ผ๋ž€์˜ ์›์ธ์ด๋ฉฐ ์šฐ๋ฆฌ๊ฐ€ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ง€๋‚œ๋ฒˆ์— ์šฐ๋ฆฌ๊ฐ€ ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒˆ์—๋Š” ๊ทธ๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ฅผ ์ •๋ง๋กœ ์›ํ•ฉ๋‹ˆ๋‹ค. :)

( @svlada ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” @Transactional ์„ ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค)

์˜ˆ, ํ•˜์ง€๋งŒ ๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ํ•œ, ์ด๋Š” ๋ชจ๋‘ DI ํ”„๋ ˆ์ž„์›Œํฌ(์˜ˆ: Spring)์˜ AOP ํ›„ํฌ๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. JDBI๊ฐ€ ๋ชจ๋“  ์„œ๋น„์Šค ๊ฐœ์ฒด๋ฅผ "๋ž˜ํ•‘"ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์ƒ์„ฑํ•˜์ง€ ์•Š์€ ๊ฐœ์ฒด์— ๋Œ€ํ•ด AOP์™€ ๊ฐ™์€ ์†”๋ฃจ์…˜์„ ์ œ๊ณตํ•  ๊ธฐํšŒ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด์ „ cglib ๊ตฌํ˜„์กฐ์ฐจ๋„ daos ์ž์ฒด์—์„œ @Transactional ๋งŒ ์•Œ ์ˆ˜ ์žˆ์—ˆ๊ณ  ๋ณ„๋„์˜ ์„œ๋น„์Šค ํด๋ž˜์Šค์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„์›€์ด ๋œ๋‹ค๋ฉด ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ ํŠธ๋žœ์žญ์…˜์„ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ๋ฅผ ๋“ค์–ด Spring ๋ฐ/๋˜๋Š” Guice AOP ๋ฐ”์ธ๋”ฉ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ core ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ spring ํ™•์žฅ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ•ต์‹ฌ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋›ฐ์–ด๋„˜์„ ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š์ง€๋งŒ ๊ธฐ์—ฌ๋Š” ํฌํ•จ์„ ์œ„ํ•ด ์ง„์ง€ํ•˜๊ฒŒ ๊ณ ๋ ค๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. "๋” ๊น”๋”ํ•œ" ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

์šฐ๋ฆฌ๋Š” ์ฃผ๋กœ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด cglib ์—์„œ Proxy ๋กœ ์ „ํ™˜ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. Proxy ๋Š” ์ง€์›๋˜๋Š” jdk API์ธ ๋ฐ˜๋ฉด cglib (๋˜๋Š” ๋ณด๋‹ค ๊ตฌ์ฒด์ ์œผ๋กœ asm ) ๋ชจ๋“  ์ฃผ์š” ๋ฆด๋ฆฌ์Šค(8, 9, 11, ...์— ์ค‘๋‹จ๋จ)์™€ ํ•จ๊ป˜ ์ค‘๋‹จ๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์œผ๋ฉฐ ์ด๋Š” ์œ ์ง€ ๊ด€๋ฆฌ์— ํฐ ๊ณจ์นซ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์•„๋งˆ๋„ https://github.com/jdbi/jdbi/pull/1252 ๊ฐ€ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…•,

@stevenschlansker ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‹ค์ œ๋กœ ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ JDBI์™€ ํ•จ๊ป˜ Spring์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์žˆ์œผ๋ฉฐ, ๋น„๊ต๋ฅผ ์œ„ํ•ด ์–ธ๊ธ‰ํ•œ ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” AOP๋ฅผ ์™„์ „ํžˆ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค cglib

์ด์ œ ํ•„์š”ํ•  ๋•Œ ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

         try (Handle handle = jdbi.open()) {
                handle.useTransaction(h -> {
                    AccountService accountService = new AccountServiceImpl(h.attach(AccountDao.class));                    
                    accountService.addAccount(a, u);
                });
          }

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ Mock Dao๋กœ ์„œ๋น„์Šค๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ•˜๊ณ , ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ์ตœ์ข…์ ์œผ๋กœ ์œ ์ง€ํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ธฐ๋ณธ ๋ฉ”์†Œ๋“œ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ , ์„œ๋น„์Šค ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šคํ™”์˜ ์ถ”๊ฐ€ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ํฐ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์•ผ ํ•จ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ์ฃผ์„์˜ ์ฝ”๋“œ ์˜ˆ์ œ์— ๋Œ€ํ•œ ๋น ๋ฅธ ์‘๋‹ต: try ๋ธ”๋ก์„ ๊ฑด๋„ˆ๋›ฐ๊ณ  jdbi.useTransaction() ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์ฝœ๋ฐฑ์ด ๋ฐ˜ํ™˜๋  ๋•Œ ์ž๋™์œผ๋กœ ๋‹ซํžˆ๋Š” ์ž„์‹œ ํ•ธ๋“ค์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„, PR #1579๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค -- jdbi 3.10.0์—์„œ CreateSqlObject์™€ onDemand๋Š” (๋งˆ์นจ๋‚ด) ์ž˜ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰