Tomcat JDBC의 주요 프로퍼티
Tomcat JDBC 모듈의 DataSource(org.apache.tomcat.jdbc.pool.DataSource) 클래스는 커넥션 풀 기능을 제공하는 DataSource 구현 클래스입니다. DataSource 클래스는 커넥션을 몇 개 만들지 지정할 수 있는 메서드를 제공합니다.
setInitialSize(int) | 커넥션 풀을 초기화 할때 생성할 초기 커넥션 개수 지정 기본값 : 10 |
setMaxActive(int) | 커넥션 풀에서 가져올 수 있는 최대 커넥션 개수 지정 기본 값 : 100 |
setMaxIdle(int) | 커넥션 풀에 유지할 수 있는 최대 커넥션 개수 지정 기본값 : maxActive |
setMinIdle(int) | 커넥션 풀에 유지할 최소 커넥션 개수 지정 기본 값 : initialSize |
setMaxWait(int) | 커넥션 풀에서 커넥션을 가져올 때 대기할 최대 시간을 밀리초단위로 지정 기본값 : 30,000 밀리초(30초) |
setMaxAge(long) | 최초 커넥션 연결 후 커넥션의 최대 유효 시간을 밀리초 단위로 지정 기본값 : 0 ( 유효시간 없음 ) |
setValidationQuery(String) | 커넥션이 유효한지 검사할 때, 사용할 쿼리를 지정 언제 검사할지는 별도 설정으로 지정 기본값 : null (검사하지 않음) select 1 이나 select 1 from dual과 같은 쿼리를 주로 사용 |
setValidationQueryTimeout(int) | 검사 쿼리의 최대 실행시간을 초단위로 지정 이 시간을 초과하면 검사 실패로 간주 0 이하로 지정하면 비활성화 기본값 : -1 |
setTestOnBorrow(boolean) | 풀에서 커넥션을 가져올 때 검사여부를 지정 기본값 : false |
setTestOnReturn(boolean) | 풀에서 커넥션을 반환할 때 검사 여부를 지정 기본값 : false |
setTestWhileIdle(boolean) | 커넥션이 풀에 유휴 상태로 있는 동안 검사할지 여부 지정 기본값 : false |
setMinEvictableIdleTimeMillis(int) | 커넥션 풀에 유휴 상태로 유지할 최소 시간을 밀리초 단위로 지정 testWhileIdle 이 true 이면 유휴 시간이 이 값을 초과한 커넥션을 풀에서 제거 기본값 : 60,000밀리초(60초) |
setTimeBetweenEvictionRunsMillis(int) | 커텍션 풀의 유휴 커넥션을 검사할 주기를 밀리초 단위로 지정 기본값 : 5,000밀리초(5초) 이 값을 1초 이하로 설정하면 안된다 |
위의 설정 상태를 이해하려면 우선, 커넥션의 상태를 알아야 합니다. 커넥션풀은 커넥션을 생성하고 유지합니다. 커넥션 풀에서 커넥션을 요청하면 해당 커넥션은 활성(active) 상태가 되고, 커넥션을 다시 커넥션 풀에 반환하면 유휴(idle) 상태가 됩니다.
DataSource#getConnection()을 실행하면 커넥션 풀에서 커넥션을 가져와 커넥션이 활성 상태가 됩니다.
반대로 커넥션을 종료(close)하면 커넥션은 풀로 돌아가 유휴 상태가 됩니다.
package dbquery;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.tomcat.jdbc.pool.DataSource;
public class DbQuery {
private DataSource dataSource;
public DbQuery(DataSource dataSource) {
this.dataSource = dataSource;
}
public int count() {
Connection conn = null;
try {
conn = dataSource.getConnection(); //풀에서 구함.
try (
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select count(*) from MEMBER")){
rs.next();
return rs.getInt(1);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if(conn != null) {
try {
conn.close(); //풀에 반환
} catch (SQLException e) {
}
}
}
}
}
conn = dataSource.getConnection(); //풀에서 구함.
이 코드를 실행하면 DataSource를 커넥션을 구하는데 이 때, 풀에서 커넥션을 가져옵니다. 이 시점에서 conn은 활성 상태입니다.
conn.close(); //풀에 반환
커넥션 사용이 끝나고 위 코드처럼 커넥션을 종료하면 실제 커넥션을 끊지 않고 풀에 반환합니다. 풀에 반환된 커넥션은 다시 유휴 상태가 됩니다.
maxActive는 활성 상태가 가능한 최대 커넥션 개수를 지정합니다. maxActive를 40으로 지정하면 이는 동시에 커넥션 풀에서 가져올 수 있는 커넥션 개수가 40개라는 뜻입니다.
활성상태 커넥션이 40개인데 커넥션 풀이 다시 커넥션을 요청하면 다른 커넥션이 반환될 때 까지 대기합니다. 이 대기시간을 maxWait입니다. 대기 시간 내에 풀에 반환된 커넥션이 있으면 해당 커넥션을 구하게 되고, 대기 시간 내에 반환된 커넥션이 없으면 익셉션이 발생합니다.
커넥션 풀을 사용하는 이유는 성능 때문입니다. 매번 새로운 커넥션을 생성할 때마다 연결 시간이 소모됩니다.
커넥션 풀을 사용하면 미리 커넥션을 생성했다가 필요할 때 커넥션을 꺼내 사용하므로 커넥션을 구하는 시간이 줄어 전체 응답시간도 짧아지게 됩니다. 그래서 커넥션 풀을 초기화할 때 최소 수준의 커넥션을 미리 생성하는 것이 좋습니다. 이때 생성할 커넥션 수를 initialSize로 지정합니다.
커넥션 풀에 생성된 커넥션은 지속적으로 재사용되는데, 한 커넥션이 영원히 유지되는 것은 아닙니다. DBMS 설정에 따라 일정 시간 내에 쿼리를 실행하지 않으면, 연결을 끊기도 합니다.
DBMS 설정을 5분 동안 쿼리를 실행하지 않으면 DB 연결을 끊도록 했는데, 커넥션 풀에 특정 커넥션이 5분 넘게 유휴 상태로 존재한 경우, DBMS는 해당 커넥션의 연결을 끊지만 커넥션은 여전히 풀 속에 남아있게 되고, 이 상태에서 해당 커넥션을 가져와 사용하면 연결이 끊어진 커넥션이므로 익셉션이 발생하게 됩니다.
이러한 문제를 예방하기 위해 커넥션 풀의 커넥션이 유효한지 주기적으로 검사해야 합니다.
minEvictableIdleTimeMills, timeBetweenEvictionRunsMillis, testWhileIdle 메서드를 통해 검사하면 됩니다.
10초 주기로 유휴 커넥션이 유효한지 여부를 검사하고 최소 유휴 시간을 3분으로 지정하는 예
package config;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DbConfig {
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/spring5fs?characterEncoding=utf8");
ds.setUsername("spring5");
ds.setPassword("spring5");
ds.setInitialSize(2);
ds.setMaxActive(10);
ds.setTestWhileIdle(true); //유효 커넥션 검사
ds.setMinEvictableIdleTimeMillis(1000 * 60 * 3); //최소 유휴시간 3분
ds.setTimeBetweenEvictionRunsMillis(1000 * 10); //10초주기
return ds;
}
}
'Spring' 카테고리의 다른 글
[Spring] Spring JdbcTemplate - qureyForObject 메서드 (0) | 2024.02.19 |
---|---|
[Spring] Spring JDBCTemplate 쿼리실행 (0) | 2024.02.19 |
[Spring] Spring JDBC - DB 연결해보기 (1) | 2024.02.17 |
[Spring] 스프링 DB 연동 (0) | 2024.02.16 |
[Spring] Spring AOP - @Around의 Pointcut 설정과 @Pointcut 재사용 (0) | 2024.02.16 |