Jdbi: ์ง€์› R2DBC

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

R2DBC์— ๋Œ€ํ•œ ์ง€์›์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. jdbi-r2dbc ์™€ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ:

https://r2dbc.io/
https://github.com/r2dbc

๋˜ํ•œ ๋ฐ˜์‘ํ˜• ํ”Œ๋žซํผ์˜ ์ผ๋ถ€์ธ vlingo-symbio ์—์„œ Jdbi๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ™•์ธ ํ•ด๋ด. ์ „์ฒด ํ”Œ๋žซํผ์—์„œ ํŒ€์˜ ์†๋„๋ฅผ ๋†’์ด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

https://github.com/vlingo/vlingo-symbio-jdbc/tree/master/src/main/java/io/vlingo/symbio/store/object/jdbc/jdbi

help wanted integration

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

์ด ํ‹ฐ์ผ“์„ ๋ณด๋‹ˆ ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค.

R2DBC์˜ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€๋ฅผ ๋น ๋ฅด๊ฒŒ ์‚ญ์ œํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

  • ์•„์ง ์ดˆ๊ธฐ ๋‹จ๊ณ„์ด๋ฉฐ GA๋กœ ์ „ํ™˜ํ•˜๊ธฐ ์ „์— BLOB/CLOB ๋ฐ ์ €์žฅ ํ”„๋กœ์‹œ์ € ์ง€์›๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋“œ๋ผ์ด๋ฒ„๋Š” ์™„์ „ ๋ฐ˜์‘ํ˜•์ด๋ฉฐ ์ „์ฒด I/O ๋ถ€๋ถ„์ด ์ฐจ๋‹จ๋˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ํ’€๋กœ ์ฐจ๋‹จ ์ž‘์—…์„ ์˜คํ”„๋กœ๋”ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“  R2DBC๋Š” Spring Data R2DBC, R2DBC Client(jdbi์—์„œ ์•„์ด๋””์–ด๋ฅผ ๋นŒ๋ ค์ฃผ๋Š” R2DBC SPI ์œ„์— ์žˆ๋Š” ์ž‘์€ ๋ž˜ํผ) ๋“ฑ๊ณผ ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„์—์„œ SPI๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

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

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

์ด๊ฒƒ์€ JDBC ๋ฐ˜์‘ํ˜•์„ ๊ตฌํ˜„ํ•  ๋•Œ ๊ฒฐ๊ตญ ์—ฐ๊ฒฐ/ํ•ธ๋“ค, ์„œ๋น„์Šค ์ฟผ๋ฆฌ๋ฅผ ๋ณด์œ ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜์‘ํ˜• ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋‚ด๋ณด๋‚ด๋Š” ์ด์ „ ์Šคํƒ€์ผ์˜ ์Šค๋ ˆ๋“œ ํ’€์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฐ˜์‘ํ˜•์˜ ์ด์  ์ค‘ ์ผ๋ถ€๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋ฐ˜์‘ํ˜• ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฐ˜์‘ํ˜•์ด ๋‹ฌ์„ฑํ•˜๋ ค๋Š” ํ™•์žฅ์„ฑ ์ด์ ์„ ์‹ฌ๊ฐํ•˜๊ฒŒ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” API ํ†ตํ•ฉ์„ ํ™•์‹คํžˆ ํ™˜์˜ํ•˜์ง€๋งŒ, ๋‚ด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์กฐ์‚ฌํ•œ ์ดํ›„๋กœ JDBC ์„ธ๊ณ„์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ํ•œ, ์•„๋ž˜์˜ ์ฝ”๋“œ๊ฐ€ ์—ฌ์ „ํžˆ ๊ตฌ์‹ ์Šค๋ ˆ๋“œ ์ฝ”๋“œ๋ผ๋Š” ์‚ฌ์‹ค์„ ์ˆจ๊ธฐ๋Š” ๋‹ค์†Œ ์ œํ•œ๋œ ๋ž˜ํผ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ท€ํ•˜์˜ ํ”Œ๋žซํผ์— ๋Œ€ํ•œ ์ตœ์‹  ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ œ์•ˆ์— ๊ฐ์‚ฌํ•˜์ง€๋งŒ ์šฐ๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ”Œ๋žซํผ์ด๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹Œ ๊ฑฐ์˜ ์™„์ „ํžˆ ๋…๋ฆฝํ˜•์ด๋ผ๋Š” ์ ์„ ์ž๋ž‘์Šค๋Ÿฝ๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” ์˜๊ฐ์„ ์ฐพ๊ณ  ๊ณต์œ  ๋ชฉํ‘œ๋ฅผ ์œ„ํ•ด ํ•ญ์ƒ ๊ธฐ๊บผ์ด ํ˜‘๋ ฅํ•˜์ง€๋งŒ, ์šฐ๋ฆฌ๋Š” ๋งค์šฐ ๋…๋ฆฝ์ ์ธ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. :)

์ด๋ด, ์Šคํ‹ฐ๋ธ! ๊ท€ํ•˜์˜ ์˜๊ฒฌ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ํ˜„์žฌ ์šฐ๋ฆฌ๋Š” vlingo-symbio ๊ตฌํ˜„์—์„œ ์•กํ„ฐ ๋‚ด์—์„œ ์š”์ฒญ์„ ์ง๋ ฌํ™”ํ•˜์—ฌ Reactive-over-JDBC๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ ์ œํ•œ์— ๋งž๋Š” ๋งŒํผ JDBCObjectStoreActor ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ ์•กํ„ฐ ์ž์ฒด๋Š” JDBC์— ๋™๊ธฐ์ ์œผ๋กœ ์•ก์„ธ์Šคํ•ฉ๋‹ˆ๋‹ค. ์•กํ„ฐ์—์„œ ์‹คํ–‰๋˜๋Š” ObjectStore ๊ตฌํ˜„์˜ ํด๋ผ์ด์–ธํŠธ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋˜๋Š” ๋™์•ˆ ์ฐจ๋‹จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” R2DBC๋ฅผ ์™„์ „ํžˆ ์ดํ•ดํ•˜์ง€๋Š” ๋ชปํ–ˆ์ง€๋งŒ ์™„์ „ํ•œ JDBC ๋Œ€์ฒดํ’ˆ์œผ๋กœ ์„ ์ „๋˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“œ๋ผ์ด๋ฒ„๋กœ์„œ ์™„์ „ํžˆ ๋น„๋™๊ธฐ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ Postgres ๋ฐ MS SQL Server์— ๋Œ€ํ•œ ๊ตฌํ˜„๋งŒ ์žˆ์ง€๋งŒ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ์ฆ๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. Jdbi๊ฐ€ R2DBC๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–ค ๊ฒƒ์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ง€๊ธˆ ๋‹น์‹ ์—๊ฒŒ ์˜๋ฏธ๊ฐ€ ์—†๋Š”์ง€ ์ดํ•ดํ•˜์ง€๋งŒ, ๋‚˜์ค‘์— ๊ทธ๋Ÿด ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ ์—ฌ๊ธฐ์— ์ฐธ์กฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ŠคํŠธ๋ ˆ์Šค์—†๋Š” :)

ํฅ๋ฏธ๋กญ๊ฒŒ๋„ ๊ทธ๋“ค์€ ์‹ค์ œ๋กœ ์ž์ฒด ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์—์„œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

๋ฒค์น˜๋งˆํฌ, ๊ฐœ๋… ์ฆ๋ช… ์ฝ”๋“œ ๋“ฑ์„ ์ถ”๊ฐ€๋กœ ํƒ์ƒ‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์ œํ•œ ์‚ฌํ•ญ์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. postgres์šฉ r2dbc ๋“œ๋ผ์ด๋ฒ„๋Š” BLOB ๋ฐ CLOB ์œ ํ˜•์ด ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๊ณ  ๊ด‘๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ์ž‘๋™ํ•˜๊ณ  ์ €์žฅ ํ”„๋กœ ์‹œ์ € ๋˜๋Š” CALL ๋Œ€ํ•œ ์–ธ๊ธ‰์ด ์—†์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ ์–ด๋„ ์ง€๊ธˆ์€ ๊ฐœ์ธ์ ์œผ๋กœ ์ดˆ์ ์„ ๋‹ค๋ฅธ ๊ณณ์— ๋‘๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์•ž์œผ๋กœ ๋‚˜์•„๊ฐ€๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์˜๊ฒฌ๊ณผ ๊ด€์‹ฌ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ์—ฌ๊ธฐ์—์„œ ํƒ์ƒ‰์„ ์‹œ์ž‘ํ•  ์‹œ๊ฐ„์ด ์—†๊ณ  ๋‹ค๋ฅธ ํ•ต์‹ฌ ๊ตฌ์„ฑ์›์ด ๋‹ค์Œ์„ ์ฐพ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์— ๋›ฐ์–ด.

์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ๋‹ค๋ฅธ ๊ตฌ์„ฑ์›๋“ค์ด ์ด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด๋ผ๋Š” ํˆฌํ‘œ๋งŒ ํ•ด๋„ ๋” ๋งŽ์€ ์†Œ์‹์„ ๋“ค์„ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

์ด ํ‹ฐ์ผ“์„ ๋ณด๋‹ˆ ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค.

R2DBC์˜ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€๋ฅผ ๋น ๋ฅด๊ฒŒ ์‚ญ์ œํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

  • ์•„์ง ์ดˆ๊ธฐ ๋‹จ๊ณ„์ด๋ฉฐ GA๋กœ ์ „ํ™˜ํ•˜๊ธฐ ์ „์— BLOB/CLOB ๋ฐ ์ €์žฅ ํ”„๋กœ์‹œ์ € ์ง€์›๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋“œ๋ผ์ด๋ฒ„๋Š” ์™„์ „ ๋ฐ˜์‘ํ˜•์ด๋ฉฐ ์ „์ฒด I/O ๋ถ€๋ถ„์ด ์ฐจ๋‹จ๋˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ํ’€๋กœ ์ฐจ๋‹จ ์ž‘์—…์„ ์˜คํ”„๋กœ๋”ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“  R2DBC๋Š” Spring Data R2DBC, R2DBC Client(jdbi์—์„œ ์•„์ด๋””์–ด๋ฅผ ๋นŒ๋ ค์ฃผ๋Š” R2DBC SPI ์œ„์— ์žˆ๋Š” ์ž‘์€ ๋ž˜ํผ) ๋“ฑ๊ณผ ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„์—์„œ SPI๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์ œ ์›๋ž˜ ํ”„๋กœํ† ํƒ€์ž…/๋ฐ๋ชจ ํด๋ผ์ด์–ธํŠธ ๊ณ„์ธต์ธ r2dbc-client ๊ฐ€ Jdbi์˜ API์™€ ์ •์‹ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ๋‹ค๋Š” ์ ์„ ์–ธ๊ธ‰ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ๋” ์ž์„ธํžˆ ์กฐ์‚ฌํ•˜๊ธฐ๋กœ ์„ ํƒํ•˜๋ฉด ์นœ์ˆ™ํ•˜๊ฒŒ ๋Š๊ปด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค ๐Ÿ˜„.

๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด JDBI(์˜ˆ: @hgschmie) ์—์„œ Rx ํ•ญ๋ชฉ์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. R2DBC์— ๋Œ€ํ•œ "์ง€์›"์ด ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

JDBI ์œ„์— R2DBC๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ, JDBi๊ฐ€ R2DBC Connection s๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ, Rx ์ธํ„ฐํŽ˜์ด์Šค์— ์ดˆ์ ์„ ๋งž์ถ”๊ธฐ ์œ„ํ•ด JDBI๋ฅผ ๊ต์ฒดํ•˜๋Š” ๊ฒƒ, ์•„๋‹ˆ๋ฉด... ๋‹ค๋ฅธ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

"JDBI ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋…ธ์ถœํ•˜์—ฌ JDBI์—์„œ ์‚ฌ์šฉํ•  R2DBC ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์ง€์›" ํ•œ๋‹ค๊ณ  ์ƒ๊ฐ ํ•ฉ๋‹ˆ๊นŒ?

R2DBC๋Š” JDBC์˜ ๋น„๋™๊ธฐ ๋Œ€์ฒดํ’ˆ์ž…๋‹ˆ๋‹ค.

@brianm R2DBC๋Š” ThreadPools์˜ JDBC๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. R2DBC๋Š” ๋‘ ๊ฐ€์ง€๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  1. R2DBC ๋“œ๋ผ์ด๋ฒ„๋Š” ๊ฐ I/O ๋ฐ”์ธ๋”ฉ ์ž‘์—…์— ๋Œ€ํ•ด org.reactivestreams.Publisher ์œ ํ˜•์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„์ฐจ๋‹จ ์ „์†ก ๊ณ„์ธต์„ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ์•„๋ž˜์—์„œ JDBC ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ ์ฒ˜์Œ๋ถ€ํ„ฐ ์œ ์„  ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  2. R2DBC๋Š” ํ‘œ์ค€ํ™”๋œ(๋ฒค๋” ๋…๋ฆฝ์ ์ธ) SPI๋กœ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งจ ์œ„์— ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋“œ๋ผ์ด๋ฒ„ ๊ตฌํ˜„์€ ์˜ค๋Š˜๋‚  JDBC์— ๋Œ€ํ•ด ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ƒํ˜ธ ๊ตํ™˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

JDBi๊ฐ€ R2DBC ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜์—ฌ JDBI ์œ„์— R2DBC๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ, ์ด๊ฒƒ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Project Reactor/RxJava2/Zerodep ์œ ํ˜•์„ ๋ฐ˜ํ™˜ํ•˜๋Š” R2DBC ํŠน์ • JDBI ๋ชจ๋“ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” R2DBC๊ฐ€ ๋ฌด์—‡์ธ์ง€ ํ™•์‹คํžˆ ์•Œ๊ณ  ์žˆ์œผ๋ฉฐ ๋งค์šฐ ์ข‹์€ ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

"JDBI ์ง€์›"์ด ๋ฌด์—‡์ธ์ง€ ์•Œ์•„ ๋‚ด๋ ค๊ณ  ๋…ธ๋ ฅ ์ค‘์ž…๋‹ˆ๋‹ค!

JDBI์˜ API๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ์ž‘์„ฑํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์ดˆ๋ณด์ž๋ฅผ ์œ„ํ•ด ๋‹ค์Œ์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

Jdbi jdbi = Jdbi.create("r2dbc:h2:mem:///test"); // (H2 in-memory database), obtain ConnectionFactory via ConnectionFactories.get(String url)

// Reactor style:
Flux<User> users = jdbi.withHandle(handle -> {

    return handle.execute("CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR)")

        .then(handle.execute("INSERT INTO user(id, name) VALUES (?0, ?1)", 0, "Alice"))

        .then(handle.createUpdate("INSERT INTO user(id, name) VALUES (?0, ?1)")
            .bind(0, 1)
            .bind(1, "Bob")
            .execute())
         .then(handle.createQuery("SELECT * FROM user ORDER BY name")
              .mapToBean(User.class).many());
});

// RxJava style
Flowable<User> users = jdbi.withHandle(handle -> { โ€ฆ });

์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ์ง€์›์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

public interface UserDao {
    @SqlUpdate("CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR)")
    Completable createTableRxJava();

    @SqlUpdate("CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR)")
    Mono<Void> createTableProjectReactor();

    @SqlQuery("SELECT * FROM user ORDER BY name")
    @RegisterBeanMapper(User.class)
    Flowable<User> listUsersRxJava();

    @SqlQuery("SELECT * FROM user ORDER BY name")
    @RegisterBeanMapper(User.class)
    Flux<User> listUsersProjectReactor();
}

๋‚˜๋Š” RxJava์™€ Project Reactor์— ๋Œ€ํ•ด ์ž์‹ ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋‘ API๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€ํ˜•์„ ๋‚˜์—ดํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ ์—ฌ๊ธฐ์—์„œ ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ์ œ์•ˆํ•˜๊ณ  ์žˆ๋Š”์ง€ ๋ช…ํ™•ํžˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

R2DBC๋Š” JDBC ์œ„์— ์žˆ๋Š” ๊ณ„์ธต์ž…๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ž์ฒด์ ์ธ ๊ฒƒ์ž…๋‹ˆ๊นŒ? Jdbi๋Š” ๊ทน๋‹จ์ ์œผ๋กœ JDBC์™€ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

R2DBC๋Š” JDBC ์œ„์— ์žˆ๋Š” ๋ ˆ์ด์–ด๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. R2DBC๋Š” SQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•œ ๋น„์ฐจ๋‹จ API์ด๋ฉฐ ๊ณ ์œ ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค(R2DBC ๋“œ๋ผ์ด๋ฒ„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋น„์ฐจ๋‹จ I/O ๊ณ„์ธต์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ณต๊ธ‰์—…์ฒด๋ณ„ ์™€์ด์–ด ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ž‘์„ฑ๋จ). ์›ํ•œ๋‹ค๋ฉด R2DBC๋Š” SQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ†ตํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋ฐ˜์‘ ์‚ฌ์–‘์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ œ์•ˆ์€ Jdbi์ฒ˜๋Ÿผ ๋ณด์ด๊ณ  ์ž‘๋™ํ•˜์ง€๋งŒ R2DBC ๋“œ๋ผ์ด๋ฒ„ ์•„๋ž˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” API๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. API๋Š” ์Šค์นผ๋ผ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹  Reactive Streams ์œ ํ˜•์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์„ค๋ช…ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” R2DBC ์œ„์— ์œ„์˜ ์˜ˆ์ œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ์ตœ์†Œํ•œ์˜ PoC ์—ญํ• ์„ ํ•˜๋Š” Jdbi ํฌํฌ ๋˜๋Š” ๋ถ„๊ธฐ์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฑฐ๊ธฐ์—์„œ ์šฐ๋ฆฌ๋Š” ๊ธฐ์กด JDBC ์ง€์›๊ณผ ๋ณ‘ํ–‰ํ•˜์—ฌ ํ†ตํ•ฉ์„ ํ–ฅํ•œ ๊ฒฝ๋กœ๋ฅผ ๊ฒฐ์ •ํ•˜๊ฑฐ๋‚˜ ์ด๊ฒƒ์ด ํ•˜๋“œ ํฌํฌ๋กœ ๋” ๋‚˜์„ ๊ฒƒ์ž„์„ ํ™•๋ฆฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ Matthew๊ฐ€ ์ง€์ ํ–ˆ๋“ฏ์ด ์šฐ๋ฆฌ๋Š” ํ˜„์žฌ JDBC์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๋งŽ์€ ๋…ธ๋ ฅ์ด ํ•„์š”ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ž ์žฌ์ ์œผ๋กœ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ์˜ ์žฅ๊ธฐ์ ์ธ ๋ ˆ์ด๋”์— ์ด๊ฒƒ์„ ํฌํ•จํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ๋‹นํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฐธ์—ฌ ์—†์ด๋Š” ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰๋  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@stevenschlansker ์ฒ˜์Œ์—๋Š” JDBI ์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ r2dbc ๋ชจ๋“ˆ( jdbi-r2dbc )์„ R2DBC Client์˜ ๊ธฐ์—ฌ๋กœ JDBI์— ๋‹ค์‹œ ๋„์ž…ํ•˜๋Š” pull ์š”์ฒญ/PoC์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

ConnectionFactory cf = โ€ฆ;

Rdbi rdbi = new Rdbi(cf);

rdbi.inTransaction(handle ->
    handle.execute("INSERT INTO test VALUES ($1)", 100))

    .thenMany(rdbi.inTransaction(handle ->
        handle.select("SELECT value FROM test")
            .mapResult(result -> result.map((row, rowMetadata) -> row.get("value", Integer.class)))))

    .subscribe(System.out::println);

์•„์ฃผ ๋ฉ‹์ ธ์š”. ์˜ˆ, ์ž‘์—…์ด ํ•ฉ๋ฆฌ์ ์œผ๋กœ ์›ํ™œํ•˜๊ฒŒ ํ†ตํ•ฉ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ธฐ๊บผ์ด ๋ชจ๋“ˆ์—์„œ ๋ฐฐ์–‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

Rdbi api๊ฐ€ Jdbi ์—์„œ "์˜จ" ๊ฒฝ์šฐ -- jdbi.installPlugin(...).registerRowMapper(...) ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ Rdbi ์ธ์Šคํ„ด์Šค๊ฐ€ " "์—์„œ Jdbi ๋„ ๊ตฌ์„ฑ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋˜ํ•œ <strong i="11">@SqlUpdate</strong> CompletableFuture<ResultType> doSomeWork(...); ๋˜๋Š” ์ ์ ˆํ•œ ๋ฐ˜์‘ ์œ ํ˜•์ด ๋ฌด์—‡์ด๋“  ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

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