did_story

[Spring] ์ปค๋„ฅ์…˜ ํ’€๊ณผ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ, ์™œ ํ•„์š”ํ• ๊นŒ? ๋ณธ๋ฌธ

BackEnd๐Ÿƒ/Spring boot

[Spring] ์ปค๋„ฅ์…˜ ํ’€๊ณผ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ, ์™œ ํ•„์š”ํ• ๊นŒ?

์–ด์ œ์‹œ์ž‘ 2025. 1. 20. 15:37

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ปค๋„ฅ์…˜ ํ’€๊ณผ ๋ฐ์ดํ„ฐ์†Œ์Šค์˜ ๊ฐœ๋…๊ณผ ํ•„์š”์„ฑ, ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

 


source : wearecommunity.io

1. ์ปค๋„ฅ์…˜ ํ’€(Connection Pool)์ด๋ž€?

 โžก๏ธ  ์ปค๋„ฅ์…˜ ํ’€์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด ๋‘๊ณ , ํ•„์š”ํ•  ๋•Œ ๊ฐ€์ ธ์™€์„œ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ JDBC์—์„œ DriverMaanager.getConnection()์„  ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด ๋งค๋ฒˆ ์ƒˆ๋กœ์šด DB ์—ฐ๊ฒฐ์ด ์ƒ์„ฑ๋˜๋Š”๋ฐ, ์ด๋Š” ์„ฑ๋Šฅ์ƒ ํฐ ๋ถ€๋‹ด์ด ๋œ๋‹ค!

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

๐Ÿ“Œ ์ปค๋„ฅ์…˜ ํ’€์ด ํ•„์š”ํ•œ ์ด์œ 

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

๐Ÿ“Œ ์ปค๋„ฅ์…˜ ํ’€์˜ ๋™์ž‘ ๊ณผ์ •

  1. ์• ํ”Œ๋ ˆ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ, ์„ค์ •๋œ ๊ฐœ์ˆ˜๋งŒํผ ์ปค๋„ฅ์…˜์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด ๋‘”๋‹ค. (MySQL์€ 10๊ฐœ๋กœ ์•Œ๊ณ  ์žˆ์–ด์š”!)
  2. ํด๋ผ์ด ์–ธํŠธ๊ฐ€ DB ์—ฐ๊ฒฐ์„ ์š”์ฒญํ•˜๋ฉด ํ’€์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปค๋„ฅ์…˜์„ ์ œ๊ณตํ•œ๋‹ค.
  3. ์‹œ์šฉ์ด ๋๋‚œ ์ปค๋„ฅ์…˜์€ close()๋ฅผ ํ˜ธ์ถœํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š๊ณ  ๋‹ค์‹œ ํ’€์— ๋ฐ˜ํ™˜๋œ๋‹ค.
  4. ํ’€์˜ ์„ค์ •์— ๋”ฐ๋ผ ์ผ์ •์‹œ๊ฐ„ ๋™์•ˆ ์‚ฌ์šฉ๋˜์ง€ ์•Š์€ ์ปค๋„ฅ์…˜์€ ์ž๋™์œผ๋กœ ํ•ด์ œ๋˜๊ฑฐ๋‚˜ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ์ปค๋„ฅ์…•์„ ์ถ”๊ฐ€๋กœ ์ƒ์„ฑํ•œ๋‹ค. 

๐Ÿ“Œ ์ปค๋„ฅ์…˜ ํ’€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๋Œ€ํ‘œ์ ์ธ ์ปค๋„ฅ์…˜ ํ’€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • HikariCP (Spring Boot ๊ธฐ๋ณธ ์ปค๋„ฅ์…˜ ํ’€, ์„ฑ๋Šฅ ์šฐ์ˆ˜, (2025.01.20 ๊ธฐ์ค€ ์ด๊ฒƒ์„ ์ฃผ๋กœ ์จ์™”์–ด์š”!))
  • Apache Commons DBCP
  • C3 P0
  • Tomcat JDBC Connection Pool

2. ๋ฐ์ดํ„ฐ์†Œ์Šค(DataSource)๋ž€?

โžก๏ธ  ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ž€ JDBC์—์„œ ์ปค๋„ฅ์…˜ ํ’€์„ ๊ด€๋ฆฌํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ๊ธฐ์กด์˜ DriverManager๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์—ฌ ์ปค๋„ฅ์…˜์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ DataSource๋Š” ์ปค๋„ฅ์…˜ ํ’€์„ ํ†ตํ•ด ํšจ์œจ์ ์ธ ์—ฐ๊ฒฐ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ๋„์™€์ค€๋‹ค.

์ฆ‰, DataSource๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ์„ฑ์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์„ค์ • ํŒŒ์ผ์„ ํ†ตํ•ด ์ปค๋„ฅ์…˜ ์ •๋ณด๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. 

๐Ÿ“Œ DataSource๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • ์ปค๋„ฅ์…˜ ํ’€์„ ์‰ฝ๊ฒŒ ํ™œ์šฉ ๊ฐ€๋Šฅ: DataSource๋ฅผ ํ†ตํ•ด HikariCP, DBCP ๊ฐ™์€ ์ปค๋„ฅ์…˜ ํ’€์„ ์†์‰ฝ๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ๋ถ„๋ฆฌ: DB ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์—์„œ ๋ถ„๋ฆฌํ•˜์—ฌ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ํ•œ๋‹ค.
  • ๋ณด์•ˆ ๊ฐ•ํ™”: DB ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ์™ธ๋ถ€ ์„ค์ • ํŒŒ์ผ์— ์ €์žฅํ•˜์—ฌ ์†Œ์Šค ์ฝ”๋“œ์— ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“Œ Spring Boot์—์„œ DataSource ์„ค์ •

Spring Boot์—์„œ๋Š” application.properties ๋˜๋Š” application.yml์—์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ DataSource๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

    ๐Ÿ“Œ HikariCP๋ฅผ ์ด์šฉํ•œ ์„ค์ • (Spring Boot ๊ธฐ๋ณธ๊ฐ’)

# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/{my-database}
spring.datasource.username={my-username}
spring.datasource.password={my-password}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.maximum-pool-size=10

โ“: ์œ„ ์„ค์ •์„ ์ ์šฉํ•˜๋ฉด Spring Boot๋Š” ์ž๋™์œผ๋กœ HikariCP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปค๋„ฅ์…˜ ํ’€์„ ๊ด€๋ฆฌํ•œ๋‹ค.


3. ํŠธ๋žœ์žญ์…˜(Transaction)์ด๋ž€? 

โžก๏ธ  ํŠธ๋žœ์žญ์…˜์€(Transaction)์€ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ์ผ๋ จ์˜ ์ž‘์—…์„ ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์  ๋‹จ์œ„๋กœ ๋ฌถ๋Š” ๊ฐœ๋…์ด๋‹ค. ํŠธ๋žธ์Ÿ‰์…˜์€ ๋ฐ˜๋“œ์‹œ ์ˆ˜ํ–‰๋˜๊ฑฐ๋‚˜, ์‹คํŒจ์‹œ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค!

๐Ÿ“Œ ํŠธ๋žœ์žญ์…˜์˜ ํŠน์ง• (ACID ์›์น™)

  • ์›์ž์„ฑ(Atomicity): ๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฒฝํ•˜๊ฒŒ ์ˆ˜ํ–‰๋˜๊ฑฐ๋‚˜ ์ „ํ˜€ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.
  • ์ผ๊ด€์„ฑ(Consistency): ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋œ ํ›„ ๋ฐํ‹ฐ์–ด ๋ฌด๊ฒฐ์„ฑ์ด ์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค.
  • ๊ณ ๋ฆฝ์„ฑ(Isolation): ๊ฐ ํŠธ๋žœ์žญ์…˜์€ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค.
  • ์ง€์†์„ฑ(Durability): ์› ํŠธ๋žœ์žญ์…˜์ด ์„ฑ๊ณต์ €๊ธ๋กœ ์ˆ˜ํ–‰๋˜๋ฉด ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋Š” ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅ๋œ๋‹ค.

๐Ÿ“Œ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ์˜ˆ์ œ (Spring Boot & JDBC)

@Transactional
public void increaseFolderCount(Integer folderId) {
    // 1๏ธโƒฃ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ (์—†์œผ๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ)
    Folder folder = folderRepo.findById(folderId)
            .orElseThrow(() -> new EntityNotFoundException("ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: " + categoryId));

    // 2๏ธโƒฃ ์ฝ˜ํ…์ธ  ๊ฐœ์ˆ˜ ์ฆ๊ฐ€
    folder.increaseFolderCount();

    // 3๏ธโƒฃ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ €์žฅ (ํŠธ๋žœ์žญ์…˜์— ์˜ํ•ด ์ž๋™ ์ปค๋ฐ‹ ๋˜๋Š” ๋กค๋ฐฑ)
    folderRepo.save(folder);
}

โ“: ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜ ์˜ˆ์ œ ์ฝ”๋“œ!

 

  • "์กฐํšŒ → ๋ณ€๊ฒฝ → ์ €์žฅ"์ด ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌ๋จ (์ค‘๊ฐ„์— ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ๋กค๋ฐฑ)
  • @Transactional์ด ์ด๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์„ ๋ณด์žฅํ•จ.