๐ Spring ์ปค๋ฅ์ ํ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ ์ค์ ๋ฐฉ๋ฒ (HikariCP, DBCP, Tomcat JDBC ์๋ฒฝ ์ ๋ฆฌ)
์คํ๋ง(Spring)์์ ์ปค๋ฅ์ ํ์ ์ฌ์ฉํ ๋ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ(Validation Query)๋ฅผ ์ค์ ํ์ง ์์ผ๋ฉด, ์ค๋๋ DB ์ฐ๊ฒฐ๋ก ์ธํด SQL Error, Connection reset, HikariPool connection timeout๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด ํฌ์คํ ์์๋ HikariCP, Apache DBCP2, Tomcat JDBC ๋ฑ์์ ์ปค๋ฅ์ ํ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ์ฝ๋์ ํจ๊ป ์ ๋ฆฌํ์ต๋๋ค.
๐ ์ปค๋ฅ์ ํ๊ณผ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ๊ฐ ์ค์ํ ์ด์
✔ ์ปค๋ฅ์ ํ(Connection Pool)์ด๋?
์ปค๋ฅ์ ํ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฐ๊ฒฐ์ ๋ฐ๋ณต ์์ฑํ์ง ์๊ณ ์ฌ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ๋์ด๋ ๊ธฐ์ ์ ๋๋ค. ๋ํ์ ์ธ ์ปค๋ฅ์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก๋ HikariCP, Apache Commons DBCP, Tomcat JDBC๊ฐ ์์ต๋๋ค.
✔ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ(Validation Query)์ ์ญํ
DB ์ปค๋ฅ์ ์ด ์ ํจํ์ง ๊ฒ์ฌํ๊ธฐ ์ํด ์คํํ๋ ๋จ์ ์ฟผ๋ฆฌ๋ก, ๋น์ ์์ ์ธ ์ฐ๊ฒฐ์ ์ฌ์ ์ ๊ฐ์งํด ์ค๋ฅ๋ฅผ ๋ฐฉ์งํฉ๋๋ค. ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค
- DB ์๋ฒ๊ฐ ์ฐ๊ฒฐ์ ๋์๋๋ฐ ์ปค๋ฅ์ ํ์ ์ธ์ํ์ง ๋ชปํ ๊ฒฝ์ฐ
- ์ฌ์์์ด๋ ๋คํธ์ํฌ ์ด์๋ก ์ฐ๊ฒฐ์ด ๋ฌดํจํ๋ ๊ฒฝ์ฐ
- "HikariPool-1 - Connection is not available" ์๋ฌ ๋ฐ์ ์
✅ DB๋ณ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ ์์
DBMS | ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ |
MySQL | SELECT 1 |
PostgreSQL | SELECT 1 |
Oracle | SELECT 1 FROM DUAL |
H2 | SELECT 1 |
MSSQL | SELECT 1 ๋๋ SELECT 1 AS result |
✅ Spring์์ ์ปค๋ฅ์ ํ ์ ํจ์ฑ ์ฟผ๋ฆฌ ์ค์ ๋ฐฉ๋ฒ
1️⃣ HikariCP ์ค์ (Spring Boot ๊ธฐ์ค)
Spring Boot์์ application.properties ๋๋ Java Config๋ก ์ค์ ๊ฐ๋ฅํ๋ฉฐ, HikariCP๋ ๊ธฐ๋ณธ ์ปค๋ฅ์ ํ์ ๋๋ค.
๐น application.properties ์ฌ์ฉ ์
spring.datasource.hikari.validation-timeout=5000
spring.datasource.hikari.connection-test-query=SELECT 1
๐น Java ์ฝ๋๋ก ์ค์ ์
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("password");
// ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ ์ค์
config.setConnectionTestQuery("SELECT 1");
config.setValidationTimeout(5000);
return new HikariDataSource(config);
}
๐ก Hikari๋ connectionTestQuery ์์ด๋ isValid()๋ฅผ ์ฌ์ฉํ์ง๋ง, ๋ช ์์ ์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ์ง์ ํ๋ฉด ์์ ์ฑ์ด ๋ ๋์ต๋๋ค.
2️⃣ Apache Commons DBCP2 ์ค์ (XML ๋๋ Java Config)
๐น XML ์ค์ ์์
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="user"/>
<property name="password" value="password"/>
<!-- ์ ํจ์ฑ ๊ฒ์ฌ -->
<property name="validationQuery" value="SELECT 1"/>
<property name="testOnBorrow" value="true"/>
</bean>
๐น Java ์ค์ ์์
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/mydb");
dataSource.setUsername("user");
dataSource.setPassword("password");
dataSource.setValidationQuery("SELECT 1");
dataSource.setTestOnBorrow(true);
3️⃣ Tomcat JDBC ์ค์
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.test-on-borrow=true
๋๋ XML์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ ์ ์์ต๋๋ค
<property name="validationQuery" value="SELECT 1"/>
<property name="testOnBorrow" value="true"/>
๐จ ์ ์ ์ฌํญ
- ๋๋ฌด ์์ฃผ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๋ฉด ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. ์ ์ ํ validation interval ์ค์ ์ด ํ์ํฉ๋๋ค.
- ์ฟผ๋ฆฌ๋ ์ต๋ํ ๋น ๋ฅด๊ฒ ์คํ ๊ฐ๋ฅํ ๋จ์ ์ฟผ๋ฆฌ๋ก ์์ฑํด์ผ ํฉ๋๋ค.
- ์ฌ์ฉํ๋ DBMS์ ๋ฐ๋ผ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ์ด ๋ค๋ฅด๋ ๋ฐ๋์ ํ์ธํ์ธ์.
✅ ๋ง๋ฌด๋ฆฌ
Spring์์ ์ปค๋ฅ์ ํ ์ค์ ์ ์ ํจ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ฉด, ๋ฌดํจ ์ปค๋ฅ์ ์ผ๋ก ์ธํ ์ฅ์ ๋ ์์ธ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๋ฐฉ์งํ ์ ์์ต๋๋ค. ํนํ ์ฅ์๊ฐ ์ ์ง๋๋ ์๋น์ค๋ ๋ฐฐ์น ์ฒ๋ฆฌ, AWS RDS ํ๊ฒฝ์์๋ ํ์์ ์ธ ์ค์ ์ ๋๋ค.