간단한 ConnectionPool을 구현해보기 앞서 JDBC
1. JDBC API
JDBC란 Java DataBase Connectivity로 자바에서 다양한 종류의 데이터베이스에 접속하고 SQL문을 수행하여 처리하고자 할 때 사용되는 표준 SQL 인터페이스이다.
즉, DBMS 제공업체(벤더)는 이 JDBC API 인터페이스 규칙에 따라 만든 구현체인 driver를 제공하며,
이를 통해 Java 개발자는 표준 인터페이스를 사용하여 다양한 데이터베이스 벤더의 JDBC 드라이버를 사용할 수 있다.
JDBC API를 사용하면 프로그램이 특정 데이터베이스와 독립적으로 동작할 수 있어, 데이터베이스를 변경하더라도 코드 수정을 최소화할 수 있다.
2. JDBC Driver
JDBC 드라이버는 특정 데이터베이스 벤더가 제공하는 JDBC API를 구현한 클래스들의 집합입니다.
각 데이터베이스 벤더는 자체적인 JDBC 드라이버를 제공하며, 이 드라이버는 해당 데이터베이스와의 통신을 담당합니다.
JDBC 드라이버는 JDBC API를 구현하여 Java 언어와 데이터베이스 간의 상호 작용을 가능하게 합니다.
데이터베이스 벤더는 JDBC 드라이버를 개발하여 사용자가 데이터베이스에 액세스할 수 있도록 제공합니다.
3. DriverManager
DriverManager 클래스는 JDBC 드라이버를 관리하고, 데이터베이스와의 연결을 설정하는 역할을 한다.
애플리케이션은 DriverManager를 사용하여 데이터베이스에 연결하고, Connection 객체를 가져올 수 있다.
DriverManager는 getConnection() 메서드를 통해 데이터베이스 연결을 설정하고, 해당 연결에 대한 Connection 객체를 반환한다.
4. Connection
Connection 인터페이스는 데이터베이스와의 연결을 나타냅니다.
애플리케이션은 Connection 객체를 사용하여 데이터베이스와의 통신을 수행합니다. 이를 통해 SQL 쿼리를 실행하고, 트랜잭션을 관리하며, 데이터를 읽고 쓸 수 있습니다.
JDBC는 각각의 데이터베이스에 대해 Connection 객체를 생성하고 관리합니다.
5. ConnectionPool
ConnectionPool은 데이터베이스 연결을 관리하고 재사용하는 기능을 제공합니다.
일반적으로 데이터베이스와의 연결은 비용이 많이 드는 작업이므로, ConnectionPool을 사용하여 연결을 생성 및 소멸하는 비용을 줄일 수 있습니다.
ConnectionPool은 미리 설정된 일정한 수의 Connection 객체를 만들어 두고, 필요할 때마다 이를 재사용하여 데이터베이스와의 통신을 수행합니다.
이를 통해 애플리케이션의 성능을 향상시키고, 데이터베이스 서버의 부하를 줄일 수 있습니다.
6. 간단한 ConnectionPool 구현하기
구현해볼 ConnectionPool에서는 미리 Connection을 생성하지는 않지만 Connection 객체가 생성되면 close() 메소드 호출시 Connection을 배열에 다시 반납하며, ThreadLocal 객체를 생성하여 해당 스레드와 Connection을 매핑하는 방법으로 구현하였습니다.
package dbConnectionPool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class DBConnectionPool implements ConnectionPool{
private static final ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
private String jdbcUrl;
private String username;
private String password;
private static final List<Connection> connections = new ArrayList<>();
public DBConnectionPool(String jdbcUrl, String username, String password) {
this.jdbcUrl = jdbcUrl;
this.username = username;
this.password = password;
}
public Connection getConnection() throws SQLException {
Connection con = connectionThreadLocal.get();
if (con == null) {
if (connections.size() > 0) {
con = connections.remove(0);
} else {
con = new ConnectionProxy(DriverManager.getConnection(jdbcUrl, username, password), this);
connections.add(con);
}
connectionThreadLocal.set(con);
}
return con;
}
public void returnConnection(Connection con) {
//현재 스레드에 connection을 비운다.
connectionThreadLocal.remove();
connections.add(con);
}
public void closeAll() {
for (Connection connection : connections) {
((ConnectionProxy)connection).realClose();
}
}
}
package dbConnectionPool;
import java.sql.Connection;
public interface ConnectionPool {
Connection getConnection() throws Exception;
void returnConnection(Connection con);
}
package dbConnectionPool;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConnectionProxy implements Connection {
private Connection original;
private ConnectionPool connectionPool;
DriverManager dm;
public ConnectionProxy(Connection original, ConnectionPool connectionPool) {
this.original = original;
this.connectionPool = connectionPool;
}
public void realClose() {
try {
original.close();
} catch (SQLException e) {
}
}
@Override
public void close() throws SQLException {
if (original.getAutoCommit()) {
connectionPool.returnConnection(original);
}
}
// 이하 Connection 인터페이스의 메소드 생략
'Java' 카테고리의 다른 글
사용자가 여러번 클릭할 수 있는 버튼에 대한 요청을 보내는 시점 문제 (0) | 2024.05.29 |
---|---|
Server Side Rendering 방식의 웹 앱에서 JWT을 사용하는 SpringSecurity 적용의 어려움 (0) | 2024.05.27 |