Connection Pool인 HikariCP는 Connection 생성에 이용된다.
build.gradle의 dependencies에 라이브러리를 추가하고 반영한다.
dependencies{
compileOnly('javax.servlet:javax.servlet-api:4.0.1')
implementation group: 'com.zaxxer', name: 'HikariCP', version:'5.0.0'
}
Connection Pool 이용하기
HikariCP를 이용하려면 HikariConfig라는 타입의 객체를 생성해주어야 한다.
HikariConfig는 Connection Pool을 설정하는데 있어서 필요한 정보를 가지고 있는 객체로 이를 이용해 HikariDataSource라는 객체를 생성한다.
HikariDataSource는 getConnection()을 제공하여 이를 이용해 Connection객체를 얻어서 사용할 수 있다.
@Test
public void testHikariCP() throws Excepiton{
HikariConfig config = new HikariConfig();
config.setDriverClassName("org.mariadb.jdbc.Driver");
config.setJdbcUrl(jdbc:mariadb://localhost:3306/pracdb);
config.setUsername("name");
config.setPassword("password");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource ds = new HikariDataSource(config);
Connection connection = ds.getConnection();
System.out.println(connection);
connection.close();
}
DB연결을 많이 할수록 HikariCP를 이용하는 것과 사용하지 않는 것에는 성능 차이가 상당하다. 특히 DB가 원격지에 떨어져 있는 경우, 네트워크 연결에 더 많은 시간을 소비해야 하기 때문에 이 차이는 더 커진다.
TodoDAO와 @Cleanup
HikariCP를 이용할 수 있게 되면 실제 SQL 처리를 전담하는 TodoDAO를 구성한다.
이것은 TodoService와 연동되어 최종적으로 다음과 같은 형태를 지닌다
TodoService <-> TodoDAO <-> DB
TodoDAO에서는 필요한 작업을 수행할 때 HikariDataSource를 이용한다. 따라서 처리를 쉽게 사용할 수 있도록 enum으로 ConnectionUtil 클래스를 구성하여 사용하는 것을 추천한다.
(예시 코드는 생략)
ConnectionUtil은 하나의 객체를 만들어 사용하는 방식으로 구성되며 HikariConfig를 이용해 하나의 HikariDataSource를 구성한다.
HikariDataSource는 getConnection()을 통해 사용하게 되며, 외부에서는 ConnectionUtil.INSTANCE.getConnection()을 통해 Connection을 얻을 수 있도록 한다.
TodoDAO에 ConnectionUtil을 사용하여 코드를 추가한다.
Ex)
pulbic class TodoDAO{
public String getTime(){
String now = null;
try(Connection connection = ConnectionUtil.INSTANCE.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("select now()");
ResultSet resultSet = preparedStatement.executeQuery();
){
resultSet.next();
now = resultSet.getString(1);
} catch(Exception e){
e.printStackTrace();
}
return now;
}
}
getTime()을 try-with-resources 기능을 이용해 try()내에 선언된 변수들이 자동으로 close() 될 수 있는 구조로 작성.(try() 내에 선언된 변수들은 모두 AutoCloseable이라는 인터페이스를 구현한 타입이어야 한다.)
DAO 작성 후, 테스트 코드를 이용해 문제가 없는지 확인하는 것을 추천!
Lombok의 @Cleanup
위 방식도 좋지만, Lombok의 @Cleanup을 이용하면 좀 더 깔끔한 코드를 만들 수 있다.
try-catch 문 안에 다시 try-catch를 해야 하는 경우가 있기 때문이다.
바꿔보겠다.
Ex)
public String getTime() throws Exception{
@Cleanup Connection connection = ConnectionUtil.INSTANCE.getConnection();
@Cleanup PreparedStatement preparedStatement = connection.prepareStatement("select now()");
@Cleanup ResultSet resultSet = preparedStatement.executeQuery();
resultSet.next();
String now = resultSet.getString(1);
return now;
}
간결함의 차이가 보이시나요~?
@Cleanup을 이용하면 Lombok에 종속적인 코드를 작성하게 된다는 점도 있지만, 최소한의 코드로 close()가 보장되는 코드를 작성할 수 있다는 장점이 있다.