JiwonDev

DB ํŠธ๋žœ์žญ์…˜๊ณผ ์ปค๋„ฅ์…˜ ์ดํ•ดํ•˜๊ธฐ

by JiwonDev

https://www.youtube.com/watch?v=urpF7jwVNWs&list=PLwouWTPuIjUg0dmHoxgqNXyx3Acy7BNCz&index=6 

 

# ํŠธ๋žœ์žญ์…˜์˜ ๊ฐœ๋…

  • ์—ฌ๋Ÿฌ ์ฝ๊ธฐ/์“ฐ๊ธฐ๋ฅผ ๋…ผ๋ฆฌ์ ์œผ๋กœ ํ•˜๋‚˜๋กœ ๋ฌถ์€ ๊ฒƒ
  • ๋ชจ๋‘ ์ ์šฉ๋˜๊ฑฐ๋‚˜(Commit) ๋ชจ๋‘ ์ทจ์†Œ๋˜๊ฑฐ๋‚˜(Rollback)
  • ACID (์›์ž์„ฑ, ์ผ๊ด€์„ฑ, ๋…๋ฆฝ์„ฑ, ์ง€์†์„ฑ)
  • ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ๋ฌธ์ œ๋ฅผ DB๊ฐ€ ๋Œ€์‹ ํ•ด์คŒ

 


# ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„๋Š” ์ปค๋„ฅ์…˜์„ ๋”ฐ๋ผ๊ฐ„๋‹ค.

  • [app1] ์€ 5. SQL์„ ์‹คํ–‰ํ•˜๋‹ค๊ฐ€ ์˜ค๋ฅ˜๋ฐœ์ƒ -> 6.Rollback
  • [app1]์—์„œ ์‹คํ–‰ํ•œ [4.method]๋„ ๋กค๋ฐฑ๋ฌ์œผ๋ฉด ์ข‹๊ฒ ์Œ
  • ํ•˜์ง€๋งŒ ํ˜„์‹ค์€? ๋กค๋ฐฑ ๋˜์ง€ ์•Š์Œ. DB์— ๋ฐ˜์˜๋˜์–ด์žˆ์Œ.

 

 


# ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ

์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ๊ณ ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒํ•ด์•ผํ• ๊นŒ => ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ

2021.08.18 - [Backend/Spring Core] - @Transactional ์˜ ๋™์ž‘์›๋ฆฌ, ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €

 

 


#Global Transaction (๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)

๊ทธ๋‚˜๋งˆ ๊ฐ™์€ DB์—์„œ ์ด๋Ÿฐ๊ฑฐ๋ฉด ๋‹คํ–‰์ด๋‹ค. ๋งŒ์•ฝ ์™ธ๋ถ€ API๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ๋กค๋ฐฑ์ด ํ„ฐ์ง„๋‹ค๋ฉด?

์™ธ๋ถ€ API๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ์ˆœ์„œ๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ [์™ผ์ชฝ]์ด๋ผ๊ณ  ํ•ด์„œ 100% ์•ˆ์ „ํ•œ๊ฑด ์•„๋‹˜.

 

@ Global Transaction

  • ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ž์› (DB, ๋ฉ”์‹œ์ง•ํ)๋ฅผ ํ•œ ํŠธ๋žœ์žญ์…˜์— ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌ
  • ๊ฐ ์ž์›์ด 2PC(2-phase commit)์„ ์ง€์›ํ•ด์•ผํ•จ
  • Global Tansaction manager๊ฐ€ ํ•„์š”
  • ์œ„์˜ ์˜ˆ์ œ์™€ ๊ฐ™์€ ๋‘ ๊ฐœ ์ด์ƒ์˜ ์ž์—ฐ์—์„œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ๊ฐ€ ์‰ฌ์›Œ์ง

2PC ํ”„๋กœํ† ์ฝœ ์•Œ๊ณ ๋ฆฌ์ฆ˜, ๋”ฐ๋กœ ๊ณต๋ถ€ํ•  ํ•„์š”๋Š” ์—†๋‹ค.

๊ทผ๋ฐ ์™œ ์•ˆ์“ฐ๋‚˜์š”? => ์„ฑ๋Šฅ์ด ๊ตฌ๋ ค์ง. MSA ๊ตฌ์กฐ์—์„œ๋Š” ์•„์˜ˆ ์‚ฌ์šฉ๋ถˆ๊ฐ€๋Šฅ

์ด๋ฒคํŠธ, ๋น„๋™๊ธฐ ๋ฉ”์‹œ์ง•๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ์ˆ˜๋‹จ์ด ๋” ํ˜„์‹ค์ ์ด๋‹ค.

 


# ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ

2021.08.10 - [๊ธฐ๋ณธ ์ง€์‹/CS ๊ธฐ๋ณธ์ง€์‹] - ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ์ˆ˜์ค€(DB Isolation Level)

๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด?

  • ๋‹ด๋‹น์ž๋Š” ๋ฐ˜๋“œ์‹œ 1๋ช…์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค.
  • ๋‹ด๋‹น์ž๋Š” ํ‡ด๊ทผํ•˜๊ธฐ ์ „, DB์— ๋‹ค๋ฅธ ๋‹ด๋‹น์ž๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ ํ›„ ํ‡ด๊ทผํ•ด์•ผํ•œ๋‹ค.
  • ๊ทผ๋ฐ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ํ„ฐ์ง„๋‹ค๋ฉด?

์ž‰..์กฐํšŒํ• ๋• ๋‚˜ ๋บด๊ณ ๋„ ๋ถ„๋ช… 1๋ช…์ด ๋”์žˆ์—ˆ๋Š”๋ฐ??

 

# ๊ฒฝ์Ÿ ์ƒํƒœ (Race Condition), ๋™์‹œ์„ฑ ๋ฌธ์ œ

ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ : ํŠธ๋žœ์žญ์…˜์„ ์„œ๋กœ ๊ฒฉ๋ฆฌํ•ด์„œ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์˜ํ–ฅ ์ฃผ์ง€ ๋ชปํ•˜๊ฒŒ ํ•จ.

  • ๊ทธ๋ƒฅ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋ฉด ์•ˆ๋˜์š”? => ํ•œ ๋ฒˆ์— ํ•œ ๊ฐœ์˜ ํŠธ๋žœ์žญ์…˜๋งŒ ์ฒ˜๋ฆฌ๊ฐ€๋Šฅ. ์„ฑ๋Šฅ์ด ๊ตฌ๋ฆผ์ปค๋ฐ‹๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ

 

@ ๋ฌธ์ œ1: ์ปค๋ฐ‹๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ (dirty read)

์ปค๋ฐ‹๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๋ฒ„๋ฆฌ๋Š” ๊ฒฝ์šฐ.

 

@ ๋ฌธ์ œ2: ์ปค๋ฐ‹๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ ๋ฎ์–ด์“ฐ๊ธฐ (dirty write)

๋ฌธ์ œ 1,2๋Š” Read Committed๋กœ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ

  • ์ปค๋ฐ‹๋œ ๊ฐ’๊ณผ ํŠธ๋žœ์žญ์…˜ ์ง„ํ–‰ ์ค‘์ธ ๊ฐ’์„ ๋”ฐ๋กœ ๋ณด๊ด€ (์ปค๋ฐ‹ ๋ฐ์ดํ„ฐ๋งŒ ์ฝ๊ธฐ)
  • ํ–‰ ๋‹จ์œ„ ์ž ๊ธˆ ์‚ฌ์šฉ, ํ•ด๋‹น ํ–‰์„ ์ˆ˜์ •ํ•˜๋Š” ํŠธ๋žœ์žญ์…˜์ด ๋๋‚  ๋•Œ ๊นŒ์ง€ ๋Œ€๊ธฐ (์ปค๋ฐ‹ ๋ฐ์ดํ„ฐ๋งŒ ์“ฐ๊ธฐ)

@ ๋ฌธ์ œ3: ์ฝ๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ1 (read skew, ์ฝ๋Š” ์‹œ์ ์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€œ)

๋Œ€ํ‘œ์ ์ธ ์ •ํ•ฉ์„ฑ ๋ฌธ์ œ. ํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ ๊ฐ™์€ ๊ฐ’์„ ์ฝ์—ˆ๋Š”๋ฐ ๋‹ค๋ฅธ ๊ฐ’์ด ๋‚˜์˜จ๋‹ค..?

๋ฌธ์ œ3์€ Repeatable Read๋กœ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ

ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฒŒ ํ•˜๋ฉด ๋จ. ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ์Œ

๊ตฌํ˜„ ์˜ˆ: MVCC(Multi-Version Concurrency Control)

ํ•ต์‹ฌ์€ ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฒŒํ•จ.

 


@ ๋ฌธ์ œ4: ๋ณ€๊ฒฝ ์œ ์‹ค (lost Update)

commit์ด ๊ฒน์น˜์ง€ ์•Š๋„๋ก ์ง€์—ฐ์ฒ˜๋ฆฌ ๋˜์—ˆ์ง€๋งŒ... ๊ฒฐ๊ณผ๊ฐ’์ด ์ด์ƒํ•˜๋‹ค?

 

๋ฌธ์ œ4 ํ•ด๊ฒฐ์ฑ…

  • DB๊ฐ€ ์ง€์›ํ•˜๋Š” ์›์ž์ (atomic) ์—ฐ์‚ฐ๋งŒ ์‚ฌ์šฉ

๋‹จ DB๊ฐ€ ํ•ด๋‹น ์—ฐ์‚ฐ์˜ ์›์ž์„ฑ(์—ฐ์‚ฐ ์ฒ˜๋ฆฌ๊ณผ์ •์ด ์ชผ๊ฐœ์ง€์ง€์•Š์Œ)์„ ๋ณด์žฅํ•ด์ฃผ์–ด์•ผํ•จ.

  • ๋ช…์‹œ์ ์ธ ์ž ๊ธˆ ์‚ฌ์šฉ (select ... for update)

์กฐํšŒํ•˜๊ธฐ์ „์— ์ˆ˜์ • ๋ชปํ•˜๊ฒŒ ์ž ๊ถˆ๋ฒ„๋ฆฌ๊ธฐ

  • CAS (Compare And Set)

์ฝ์€ ๊ฐ’์„ ์ €์žฅํ•ด๋†“๊ณ  ์ˆ˜์ •ํ•˜๊ธฐ์ „์— ๋‚ด๊ฐ€ ์กฐํšŒํ•œ ๊ฐ’์ด ๋งž๋Š”์ง€ ํ™•์ธ. ๋‹ค๋ฅด๋‹ค๋ฉด ๋กค๋ฐฑ or ์žฌ์‹œ๋„


@ ๋ฌธ์ œ5: ์ฝ๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ2 (phantom read)

์ฒ˜์Œ ์กฐํšŒ์—๋Š” ์—†๋˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ. (๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋Š”๊ฑด ์•„๋‹˜, ๋ฌผ๋ฆฌ์ ์ธ ๊ฒฝ์Ÿ์ƒํƒœ X)

์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋Š”๊ฑด ์•„๋‹ˆ์ง€๋งŒ.. ๋ถ„๋ช… ์ฒ˜์Œ์— ์ „์ฒด ๋ฐ์ดํ„ฐ๋Š” 3๊ฐœ์˜€๋Š”๋ฐ ๊ฐ‘์ž๊ธฐ 4๊ฐœ๊ฐ€ ๋ฌ๋„ค?

๋ฌธ์ œ5 ํ•ด๊ฒฐ์ฑ…

  • Serializable : ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜์„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ (๊ฒน์น˜์ง€ ์•Š์Œ)
  • ๋‹ค๋งŒ ์„ฑ๋Šฅ์ด ๋„ˆ๋ฌด ๊ตฌ๋ ค์„œ ์™„์ „ ์ˆœ์„œ๋Œ€๋กœ๋Š” ์‚ฌ์šฉํ•˜๋Š”๊ฑด ์•„๋‹ˆ๊ณ  ์ธ๋ฑ์Šค ๋‹จ์œ„ ์ž ๊ธˆ์ด๋‚˜ ํŠน์ • ์กฐ๊ฑด๊ธฐ๋ฐ˜ ์ž ๊ธˆ์„ ์‚ฌ์šฉ

์ธ๋ฑ์Šค์— ์ž ๊ธˆ์„ ๊ฑธ์–ด๋ฒ„๋ฆฌ๊ธฐ


# JDBC ํŠธ๋žœ์žญ์…˜๊ณผ Connection

JDBC ํŠธ๋žœ์žญ์…˜์€ ํ•˜๋‚˜์˜ Connection์„ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ๋‹ซ๋Š” ์‚ฌ์ด์— ์ผ์–ด๋‚œ๋‹ค. ์ฆ‰ ํ•œ ํŠธ๋žœ์žญ์…˜์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๋Š” ํ•œ ์ปค๋„ฅ์…˜ ๊ฐ์ฒด์— ์˜ํ•ด ์ด๋ฃจ์–ด์ง„๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋‚˜์˜ DB์ปค๋„ฅ์…˜์•ˆ์— ๋งŒ๋“ค์–ด์ง€๋Š” ํŠธ๋žœ์žญ์…˜์„ ๋กœ์ปฌ ํŠธ๋žœ์žญ์…˜์ด๋ผ ํ•œ๋‹ค. 2๊ฐœ์ด์ƒ์˜ DB์—์„œ ๋ฐœ์ƒํ•˜๋Š” ํŠธ๋žœ์žญ์…˜์˜ Commit์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฑธ ๊ธ€๋กœ๋ฒŒ ํŠธ๋žœ์žญ์…˜์ด๋ผ๊ณ  ํ•œ๋‹ค. ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ์—ˆ๋‹ค.

 

๊ทธ๋Ÿฐ๋ฐ ์„ฑ๋Šฅ์„ ์˜ฌ๋ฆฌ๊ธฐ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์„๊นŒ? ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ, user๋งˆ๋‹ค ์ปค๋„ฅ์…˜์„ ์ƒ์„ฑํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์„œ๋น„์Šค(UserSerivce)์—์„œ ์ปค๋„ฅ์…˜์„ ๊ณตํ†ต์œผ๋กœ ๋Œ๋ ค ์‚ฌ์šฉํ•˜๋Š”๊ฑฐ์ง€.

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

UserDao๋ฅผ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์„œ ํŠธ๋žœ์žญ์…˜(์ปค๋„ฅ์…˜)์ด ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ์ƒ์„ฑ๋œ๋‹ค.
์ด๋ ‡๊ฒŒ ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์–ด์„œ ํ•˜๋‚˜์˜ ์ปค๋„ฅ์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์•ˆ๋ ๊นŒ?


# ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ •

ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘๋˜๊ณ  ๋๋‚˜๋Š” ์œ„์น˜(๊ฒฝ๊ณ„)๋ฅผ ๋ฐ”๊พธ๋ฉด ๋œ๋‹ค. ํ•œ ํŠธ๋žœ์žญ์…˜์— ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค๋Š”๋ง

Connection c = dataSource.getConnection();

c.setAutoCommit(false); // ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ์‹œ์ž‘ (์ž๋™ ๊ฒฝ๊ณ„ ์ทจ์†Œ)
try {
  PreparedStatement st1 =
    c.prepareStatement("update users ...");
  st1.executeUpdate();
  
  PreparedStatement st2 =
    c.prepareStatement("delete users ...");
  st2.executeUpdate();
  
  c.commit(); // ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ๋์ง€์  (์ปค๋ฐ‹)
} catch(Exception e) {
  c.rollback(); // ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ๋์ง€์  (๋กค๋ฐฑ)
}

c.close();

# ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง(์„œ๋น„์Šค) ๋‚ด์— ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ์‘ค์…”๋„ฃ๊ธฐ

์—ด์‹ฌํžˆ ๋น„์ฆˆ๋‹ˆ์Šค ๊ฐ์ฒด์™€ DAO ๊ฐ์ฒด๋ฅผ ๋ถ„๋ฆฌํ•ด๋†จ๋”๋‹ˆ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ํŠธ๋žœ์žญ์…˜์„ ๋‹ค์‹œ ๋‹ค๋ค„์•ผํ•œ๋‹ค. ๋ฌผ๋ก  ๋ฌด์ง€์„ฑ์œผ๋กœ SuperDaoWithService ์ด๋Ÿฐ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๊ฒ ์ง€๋งŒ.. ํ˜„์‹ค์ ์œผ๋กœ ๋ง์ด ์•ˆ๋œ๋‹ค. ์ฐจ๋ผ๋ฆฌ UserService ๋‚ด๋ถ€์—์„œ Connection ๊ฐ์ฒด์™€ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ •์„ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด๋ณด๋„๋ก ํ•˜์ž.

// UserService ๊ฐ์ฒด

public void upgradeLevels() throws Exception {
  // (1) DB Connection ์ƒ์„ฑ
  // (2) ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
  try {
    // (3-1) DAO ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ add(Connection c, User user);
    // (3-2) DAO ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ get(Connection c, String id);
    // (3-3) DAO ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ update(Connection c, User user);
    // (4) ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹
  }
  catch(Exception e) {
    // (5) ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ
    throw e;
  }
  finally {
    // (6) DB Connection ์ข…๋ฃŒ
  }
}

์•ž์—์„œ ๋งํ–ˆ์ง€๋งŒ ์šฐ๋ฆฌ๋Š” SuperDaoWithService๋ฅผ ๋งŒ๋“ค๊ฒŒ ์•„๋‹ˆ๋ผ์„œ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ •(commit, rollback)๋งŒ ํ•œ ๋‹ค์Œ์— UserDao๋กœ ์ปค๋„ฅ์…˜ ๊ด€๋ฆฌ๋ฅผ ๋„˜๊ธฐ๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๊ฒƒ์ด๋‹ค.

// UserService์—์„œ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ •์„ ํ•œ ๋’ค, ํ•ด๋‹น ์ปค๋„ฅ์…˜์„ UserDao๋กœ ๋„˜๊น€
public interface UserDao {
  public void add(Connection c, User user);
  public User get(Connection c, String id);
  ...
  public void update(Connection c, User user);
}

 

@ ์ด๋ ‡๊ฒŒ ํ–ˆ์„ ๋•Œ ๋ฌธ์ œ์ 

  • DB์ปค๋„ฅ์…˜์„ ๋น„๋กฏํ•œ JdbcTemplate์˜ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๊ฒฐ๊ตญ JDBC API๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ์ดˆ๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋Œ์•„๊ฐ€์•ผ ํ•œ๋‹ค. try/catch/finally ๋ธ”๋ก์€ ์ด์ œ UserService ๋‚ด์— ์กด์žฌํ•œ๋‹ค.

  • UserService์˜ ๋ฉ”์†Œ๋“œ์— Connection ํŒŒ๋ผ๋ฉ”ํƒ€ ์ถ”๊ฐ€๋ผ์•ผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. upgardeLevels()์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์†Œ๋“œ์˜ ์–ด๋”˜๊ฐ€์—์„œ DAO๋ฅผ ํ•„์š”๋กœ ํ•œ๋‹ค๋ฉด, ๊ทธ ์‚ฌ์ด์˜ ๋ชจ๋“  ๋ฉ”์†Œ๋“œ์— ๊ฑธ์ณ์„œ Connection ๊ฐ์ฒด๊ฐ€ ์ „๋‹ฌ๋œ๋‹ค.

  • ์‹ฌ์ง€์–ด ์Šคํ”„๋ง์—์„œ๋Š” UserService๋Š” ์‹ฑ๊ธ€ํ†ค ๋นˆ์œผ๋กœ ๋˜์–ด ์žˆ์œผ๋‹ˆ ์ƒํƒœ๊ฐ’ ์ด์šฉํ•  ์ˆ˜๋„ ์—†๋‹ค. ์ฆ‰ ๊ฐ์ฒด ํ•„๋“œ์— Connection์„ ์ €์žฅํ•ด๋’€๋‹ค๊ฐ€ ๋‹ค๋ฅธ ๋ฉ”์†Œ๋“œ์—์„œ ๋Œ๋ ค์“ฐ๊ฒŒ ํ•  ์ˆ˜ ์—†๋‹ค. ๊ฒฐ๊ตญ ํŠธ๋žœ์žญ์…˜์ด ํ•„์š”ํ•œ ์ž‘์—…์— ์ฐธ์—ฌํ•˜๋Š” UserService์˜ ๋ฉ”์†Œ๋“œ๋Š” Connection ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ง€์ €๋ถ„ํ•ด์งˆ ๊ฒƒ์ด๋‹ค.

  • UserDao๋Š” ๋”์ด์ƒ ๋ฐ์ดํ„ฐ ์—‘์„ธ์Šค ๊ธฐ์ˆ ์— ๋…๋ฆฝ์ ์ด์ง€ ์•Š๋‹ค. JPA๋‚˜ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋กœ UserDao์˜ ๊ตฌํ˜„ ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  UserService ์ฝ”๋“œ๋„ ํ•จ๊ป˜ ์ˆ˜์ •๋ผ์•ผ ํ•œ๋‹ค. ๊ธฐ๊ป ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด DAO๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  DI๋ฅผ ์ ์šฉํ–ˆ๋˜ ์ˆ˜๊ณ ๊ฐ€ ๋ฌผ๊ฑฐํ’ˆ์ด ๋˜๊ณ  ๋ง ๊ฒƒ์ด๋‹ค.

  • DAO ๋ฉ”์†Œ๋“œ์— Connection ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›๊ฒŒ ํ•˜๋ฉด ํ…Œ์ŠคํŠธ์ฝ”๋“œ์—๋„ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ DB ์ปค๋„ฅ์…˜์€ ์ „ํ˜€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ  ํ…Œ์ŠคํŠธ์—์„œ UserDao๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ, ์ด์ œ๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ์ง์ ‘ Connection ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ผ์ผ์ด ๋งŒ๋“ค์–ด์„œ DAO ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ๋ชจ๋‘ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

 


# ํ•ด๊ฒฐ์ฑ… : ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”

์ด๋ฏธ ์•Œ๊ณ ์žˆ๊ฒ ์ง€๋งŒ, ์Šคํ”„๋ง์€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ‹์ง„ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

์œ„์—์„œ ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„๋ฅผ ์ง€์ •ํ•ด์คฌ์„ ๋•Œ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ์ ์€, Service๊ฐ์ฒด์—์„œ ์ปค๋„ฅ์…˜์„ ๊ด€๋ฆฌํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์Šคํ”„๋ง์ด ์ œ์•ˆํ•˜๋Š” ๋ฐฉ๋ฒ•์€, ๋…๋ฆฝ์ ์ธ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”(Transaction Sychronization) ๋ฐฉ์‹์ด๋‹ค.

 

@ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”๋ž€

ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ธฐ์œ„ํ•ด ๋งŒ๋“  Connection ๊ฐ์ฒด๋ฅผ ํŠน๋ณ„ํ•œ ์žฅ์†Œ์— ๋ณด๊ด€ํ•ด๋‘๊ณ , ์ดํ›„ DAO ๋ฉ”์„œ๋“œ์—์„œ ๊ฐ€์ ธ๋‹ค๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ด ๋•Œ, ๋™๊ธฐํ™” ์ €์žฅ์†Œ(TransactionSync)์—์„œ ์ด๋ฏธ ์‚ฌ์šฉํ•˜๊ณ ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์ปค๋„ฅ์…˜์ด ์žˆ๋‹ค๋ฉด ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฅผ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋ฐฉ์‹์ด๋ผ๊ณ  ๋งํ•œ๋‹ค. ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ์ €์žฅ์†Œ(TransactionSync)๋Š” ์ž‘์—… ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋…๋ฆฝ์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ Connection์„ ์ €์žฅ, ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์ถฉ๋Œ๋‚  ์—ผ๋ ค๋„ ์—†๋‹ค.

  1. UserService๊ฐ€ ์ปค๋„ฅ์…˜ ์ƒ์„ฑ -> TransactionSync์— ์ €์žฅ -> ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ • setAutoCommit(false)
  2. UserDao.update๋Š” ์ปค๋„ฅ์…˜์„ ๋ฐ›์•„์™€์„œ ์‚ฌ์šฉ (์ด๋ฏธ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์ด ์žˆ๋‹ค๋ฉด ๋™๊ธฐํ™”ํ•ด์„œ ํ•จ๊ป˜ ์‚ฌ์šฉ)
  3. ์ปค๋„ฅ์…˜์„ ๋‹ซ์ง€์•Š์€ ์ƒํƒœ๋กœ ์ž‘์—…์„ ๋งˆ์น˜๊ณ , TransactionSycn์— ๋‹ค์‹œ ์ปค๋„ฅ์…˜ ์ €์žฅ.

 

@ ์Šคํ”„๋ง ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ์ ์šฉ

์•„์ด๋””์–ด๋Š” ๊ธ€๋กœ๋ฒŒํ•œ ๊ณต๊ฐ„์— ํŠธ๋žœ์žญ์…˜์„ ์ž ์‹œ ์ €์žฅํ•ด๋‘”๋‹ค๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฑด ๊ธฐ์ˆ ์ ์œผ๋กœ ์ ˆ๋Œ€ ์‰ฝ์ง€ ์•Š๋‹ค. ๊ทธ๋ž˜์„œ ์Šคํ”„๋ง์€ ์•„๋ž˜์™€ ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๊ด€๋ฆฌ(TransactionSynchronizationManager)๋ฅผ ์ด์šฉ
  • ์ปค๋„ฅ์…˜์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ๋‚˜ ๋ฐ˜๋‚ฉํ•  ๋•Œ DataSourceUtils๋ผ๋Š” ์Šคํ”„๋ง ์ œ๊ณต ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉ
    => ๋™๊ธฐํ™” ๊ฐ€๋Šฅํ•œ ํŠธ๋žœ์žญ์…˜์ด ์žˆ๋‹ค๋ฉด ๊ฐ™์€ ์ปค๋„ฅ์…˜์„ ์‚ฌ์šฉ. ์—†๋‹ค๋ฉด ์ƒˆ๋กœ์šด ์ปค๋„ฅ์…˜์„ ์ƒ์„ฑ
 public void upgradeLevels() throws SQLException{
        // ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๊ด€๋ฆฌ์ž๋ฅผ ์ด์šฉํ•ด ๋™๊ธฐํ™” ์ž‘์—…์„ ์ดˆ๊ธฐํ™”
        TransactionSynchronizationManager.initSynchronization();
        // DB ์ปค๋„ฅ์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•œ๋‹ค.
        // ์ดํ›„์˜ DAO ์ž‘์—…์€ ๋ชจ๋‘ ์—ฌ๊ธฐ์„œ ์‹œ์ž‘ํ•œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ง„ํ–‰๋œ๋‹ค.
        // ์•„๋ž˜ ๋‘ ์ค„์ด DB ์ปค๋„ฅ์…˜ ์ƒ์„ฑ๊ณผ ๋™๊ธฐํ™”๋ฅผ ํ•จ๊ป˜ ํ•ด์ค€๋‹ค.
        Connection c = DataSourceUtils.getConnection(dataSource);
        c.setAutoCommit(false);

        try {
            List<User> users = userDao.getAll();
            for (User user : users) {
                if (canUpgradeLevel(user)) {
                    upgradeLevel(user);
                }
            }

            c.commit();
        }catch(Exception e) {
            c.rollback();
            throw e;
        } finally {
            // ์Šคํ”„๋ง DataSourceUtils ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ปค๋„ฅ์…˜์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ซ๋Š”๋‹ค.
            DataSourceUtils.releaseConnection(c, dataSource);
            // ๋™๊ธฐํ™” ์ž‘์—… ์ข…๋ฃŒ ๋ฐ ์ •๋ฆฌ
            TransactionSynchronizationManager.unbindResource(this.dataSource);
            TransactionSynchronizationManager.clearSynchronization();
        }
    }

 


# ํ•œ๊ฑธ์Œ ๋”, ํŠธ๋žœ์žญ์…˜ ์„œ๋น„์Šค ์ถ”์ƒํ™”

ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋“ค, ๊ฒฐ๊ตญ Connection์„ Service ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ค„์•ผํ•˜๋Š”๊ฑด ๋ณ€ํ•จ์—†๋‹ค. ์ฆ‰ DB์ ‘๊ทผ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์„œ๋น„์Šค ์˜์—ญ์—์„œ ์ฝ”๋“œ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๋ง์ด๋‹ค. ๋‹ค์‹œ ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ€๋ณด์ž. ์šฐ๋ฆฌ๊ฐ€ ์™œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”์ง€๋ฅผ.

 

@ ์Šคํ”„๋ง์˜ ํŠธ๋žœ์žญ์…˜ ์„œ๋น„์Šค ์ถ”์ƒํ™”

์Šคํ”„๋ง์€ ํŠธ๋žœ์žญ์…˜ ๊ธฐ์ˆ ์˜ ๊ณตํ†ต์ ์„ ๋‹ด์€ ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” ๊ธฐ์ˆ ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜๋ฉด ํŠน์ • ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๊ณ  ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ์„ค์ • ์ž‘์—…์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง์ด PlatformTX๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ์ด์œ ๋Š”, ๊ธฐ์กด ์ž๋ฐ” API (JTA)์˜ TransactionManager์™€ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

 

UserService๋Š” ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋ฟ, ๋” ์ด์ƒ DAO ๊ฐ์ฒด์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค. 

  • ์ดํ•ด๋ฅผ ๋•๊ธฐ์œ„ํ•ด PlatformTransactionManger๋ฅผ ์ง์ ‘ ์ ์šฉ์‹œ์ผœ๋ณด์ž

TransactionStatus ๊ฐ์ฒด

๋”๋ณด๊ธฐ
public interface TransactionStatus extends SavepointManager {
    boolean isCompleted();
    boolean isNewTransaction();
    boolean hasSavepoint();
    boolean isRollbackOnly();
    
    void setRollbackOnly();
    void flush();
}
public class UserService {
    @Autowired UserService userService;
    // ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €์˜ ๊ตฌํ˜„์ฒด๋Š” ์œ ๋™์ ์œผ๋กœ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค. JDBC์˜๊ฒฝ์šฐ DataSourceTxManager
    @Autowired PlatformTransactionManager transactionManager;
    
    //ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„์„ค์ • ์ฝ”๋“œ
    public void insertUserTest() {
        TransactionStatus status= //ํŠธ๋žœ์žญ์…˜์˜ ์‹œ์ž‘์„ ์•Œ๋ฆฐ๋‹ค.(ํŠธ๋žœ์žญ์…˜์„ ์–ป์–ด์˜ค๋Š” ์‹œ์ ์ด ์‹œ์ž‘)
                this.transactionManager.getTransaction(new DefaultTransactionDefinition());
         
         try {
            List<User> users = userDao.getAll();
            for (User user : users) {
                if (canUpgradeLevel(user)) {
                    upgradeLevel(user);
                }
            }

            transactionManager.commit(status);
        }catch(Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

์ฆ‰ DB์ ‘๊ทผ ๊ธฐ์ˆ ์ด JTA๋‚˜ Hibernate๋“ฑ์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค๊ณ  ํ•ด๋„ UserService๋Š” ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ € ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•˜๊ณ  ์žˆ๊ธฐ๋•Œ๋ฌธ์— ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ง„๋‹ค. ๋‹จ์ง€ PlatformTransactionManger ์ธํ„ฐํŽ˜์ด์Šค์— ์ฃผ์ž…ํ•˜๋Š” ๋นˆ๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋œ๋‹ค.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ