웹사이트 검색

Java의 연결 풀링


연결 풀링은 연결 개체의 풀을 의미합니다. 연결 풀링은 개체 풀 디자인 패턴을 기반으로 합니다. 개체 풀링 디자인 패턴은 새 개체를 만드는 비용(시간 및 CPU, 네트워크 및 IO와 같은 리소스)이 높을 때 사용됩니다. 개체 풀링 디자인 패턴에 따라 응용 프로그램은 미리 개체를 만들어 풀 또는 컨테이너에 배치합니다. 애플리케이션에 이러한 객체가 필요할 때마다 새 객체를 생성하는 대신 풀에서 객체를 가져옵니다.

연결 풀링 전략을 사용하는 응용 프로그램에는 재사용할 수 있는 DB 연결 개체가 이미 있습니다. 따라서 데이터베이스와 상호 작용할 필요가 있을 때 응용 프로그램은 풀에서 연결 인스턴스를 가져옵니다. 연결 풀링은 데이터베이스와 상호 작용하는 애플리케이션 성능을 향상시킵니다.

연결 풀링의 자체 구현을 만들 수 있습니다. 모든 연결 풀링 프레임워크는 세 가지 작업을 수행해야 합니다.

  • 연결 개체 만들기
  • 생성된 개체의 사용 관리 및 유효성 검사
  • 개체 해제/파기

Java에는 쉽게 사용할 수 있는 훌륭한 라이브러리 세트가 있습니다. 몇 가지 속성만 구성하면 사용할 수 있습니다.

Java 애플리케이션의 연결 풀링

아래 라이브러리를 살펴보겠습니다.

  • Apache Commons DBCP 2
  • 히카리CP
  • C3P0

아래의 예를 하나씩 살펴보겠습니다. 데모 목적으로 MySQL 데이터베이스와 Eclipse IDE를 사용합니다. 또한 JDK 1.8을 사용하여 maven 기반의 간단한 Java 프로젝트를 생성합니다.

데이터베이스 스크립트

create database empdb;

use empdb;

create table tblemployee(
                    empId integer AUTO_INCREMENT primary key,
                    empName varchar(64),
                    dob date,
                    designation varchar(64)
);

insert into  tblemployee(empId,empName,dob,designation) values (default,'Adam','1998-08-15','Manager');
insert into  tblemployee(empId,empName,dob,designation) values (default,'Smith','2001-01-11','Clerk');
insert into  tblemployee(empId,empName,dob,designation) values (default,'James','1996-03-13','Officer');

예제 프로젝트

아래 단계에 따라 새 프로젝트를 만듭니다.

  1. 이클립스 IDE를 엽니다.
  2. 파일 메뉴를 클릭하고 새로 만들기 -> Maven 프로젝트를 선택합니다.\n
  3. 아래 화면이 표시됩니다. 간단한 프로젝트 만들기 옵션을 선택하고 다음 버튼을 클릭합니다.\n

  1. 그룹 ID, 유물 ID, 이름 및 설명을 입력합니다.

마침 버튼을 클릭합니다.

  1. MySQL용 pom.xml에 다음 종속성을 추가합니다.

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.49</version>
</dependency>

  1. 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Maven -> 프로젝트 업데이트 -> 확인을 선택합니다. 모든 종속성을 다운로드합니다.

1) 아파치 커먼즈 DBCP 2

DBCP는 Apache Common Project에서 가져온 것입니다. DBCP 2.7에는 Java 8이 필요합니다. DBCP 2를 사용하려면 프로젝트에 다음 종속성을 추가해야 합니다.

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-dbcp2</artifactId>
	<version>2.7.0</version>
</dependency>

Apache DBCP 2.0은 두 가지 유형의 DataSource(BasicDataSource 및 PoolingDataSource)를 제공합니다.

BasicDataSource: 이름에서 알 수 있듯이 간단하고 가장 일반적인 사용 사례에 적합합니다. 내부적으로 우리를 위해 PoolingDataSource를 생성합니다.

연결 풀을 초기화하는 단계를 아래에서 살펴보겠습니다.

  1. BasicDataSource의 인스턴스 생성
  2. JDBC Url, 데이터베이스 사용자 이름 및 암호 지정
  3. 최소 유휴 연결 수 지정(언제든지 풀에 남아 있어야 하는 최소 연결 수)
  4. 최대 유휴 연결 수 지정(풀의 최대 유휴 연결 수)
  5. 최대 연결의 총 수를 지정합니다.

package com.journaldev.example;

/**
 * Java JDBC Connection pool using Apache commons DBCP2 example program
 * 
 * @author pankaj
 */

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.commons.dbcp2.BasicDataSource;

public class DBCP2Demo {

	private static BasicDataSource dataSource = null;

	static {
		dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
		dataSource.setUsername("root");
		dataSource.setPassword("root");

		dataSource.setMinIdle(5);
		dataSource.setMaxIdle(10);
		dataSource.setMaxTotal(25);

	}

public static void main(String[] args) throws SQLException {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = dataSource.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery("select * from tblemployee");
			while (resultSet.next()) {
				System.out.println("empId:" + resultSet.getInt("empId"));
				System.out.println("empName:" + resultSet.getString("empName"));
				System.out.println("dob:" + resultSet.getDate("dob"));
				System.out.println("designation:" + resultSet.getString("designation"));
			}
		} finally {

			resultSet.close();
			statement.close();
			connection.close();
		}
	}

}

산출:

empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer

PoolingDataSource: 더 많은 유연성을 제공합니다. DataSource를 생성하는 코드만 변경하면 됩니다. 나머지 코드는 동일하게 유지됩니다.

연결 풀을 초기화하는 단계를 아래에서 살펴보겠습니다.

  1. JDBC URL을 사용하여 ConnectionFactory 인스턴스를 생성합니다.
  2. 1단계에서 만든 ConnectionFactory 인스턴스를 사용하여 PoolableConnectionFactory 인스턴스를 만듭니다.
  3. GenericObjectPoolConfig 인스턴스 생성 및 최대 유휴, 최소 유휴 및 최대 연결 속성 설정
  4. 이제 2단계와 3단계에서 생성된 인스턴스를 사용하여 ObjectPool을 초기화합니다.
  5. 이제 풀을 PoolableConnectionFactory의 인스턴스로 설정
  6. 마지막으로 DataSource의 인스턴스를 초기화합니다.

private static DataSource dataSource = null;

	static {

		Properties properties = new Properties();
		properties.setProperty("user", "root");
		properties.setProperty("password", "root");

		ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://localhost:3306/empdb",
				properties);

		PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null);

		GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
		config.setMaxTotal(25);
		config.setMaxIdle(10);
		config.setMinIdle(5);

		ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config);
		poolableConnectionFactory.setPool(connectionPool);

		dataSource = new PoolingDataSource<>(connectionPool);

	}

2) 히카리CP

HikariCP는 빠르고 안정적이며 간단합니다. 연결 풀링에 대한 기본 솔루션 중 하나입니다. Spring Boot 2.x와 같은 프레임워크는 이를 기본 연결 관리자로 사용합니다.

HikariCP를 사용하려면 프로젝트의 pom.xml에 다음 종속성을 추가하십시오.

<dependency>
	<groupId>com.zaxxer</groupId>
	<artifactId>HikariCP</artifactId>
	<version>3.4.5</version>
</dependency>

HikariCP 구성:

아래 예제 프로그램과 같이 Java 기반 구성을 사용하거나 속성 파일을 사용하여 HikariCP를 구성할 수 있습니다. 아래 속성을 살펴보겠습니다.

  • idleTimeout: 연결 개체가 풀에서 유휴 상태로 유지될 수 있는 시간(밀리초)입니다. minimumIdle 및 maximumPoolSize 속성과 함께 작동합니다. 지정된 시간이 지나면 연결 개체가 해제됩니다.
  • connectionTimeout: 클라이언트가 풀에서 연결 개체를 기다리는 시간(밀리초)입니다. 시간 제한에 도달하면 SQL 예외가 발생합니다.
  • autoCommit: true 또는 false를 지정할 수 있으며 true로 설정하면 실행하는 모든 SQL 문을 자동으로 커밋하고 false로 설정하면 SQL 문을 수동으로 커밋해야 합니다.
  • cachePrepStmts: Prepare Statement를 위한 캐싱 활성화
  • minimumIdle: 언제든지 풀에 남아 있어야 하는 연결 개체의 최소 수입니다.
  • maximumPoolSize: 풀에 머물 수 있는 최대 연결 수입니다.

package com.journaldev.example;

/**
 * Java JDBC Connection pool using HikariCP example program
 * 
 * @author pankaj
 */

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

public class HikariCPDemo {

	private static HikariDataSource dataSource = null;

	static {
		HikariConfig config = new HikariConfig();
		config.setJdbcUrl("jdbc:mysql://localhost:3306/empdb");
		config.setUsername("root");
		config.setPassword("root");
		config.addDataSourceProperty("minimumIdle", "5");
		config.addDataSourceProperty("maximumPoolSize", "25");

		dataSource = new HikariDataSource(config);
	}

	public static void main(String[] args) throws SQLException {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = dataSource.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery("select * from tblemployee");
			while (resultSet.next()) {
				System.out.println("empId:" + resultSet.getInt("empId"));
				System.out.println("empName:" + resultSet.getString("empName"));
				System.out.println("dob:" + resultSet.getDate("dob"));
				System.out.println("designation:" + resultSet.getString("designation"));
			}
		} finally {
			resultSet.close();
			statement.close();
			connection.close();
		}
	}
}

산출:

empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer

3) C3P0

C3P0은 가장 오래된 라이브러리 중 하나입니다. 일반적으로 Hibernate와 함께 사용됩니다. C3P0을 사용하기 위해서는 다음과 같은 의존성을 프로젝트에 추가해야 합니다.

<dependency>
	<groupId>com.mchange</groupId>
	<artifactId>c3p0</artifactId>
	<version>0.9.5.5</version>
</dependency>

C3P0으로 다음 속성을 구성할 수 있습니다.

  • driverClass: 기본 Jdbc 드라이버
  • jdbcUrl: 데이터베이스의 JDBC URL입니다.
  • initialPoolSize: 시작 시 풀에서 생성된 연결 수
  • acquireIncrement: 현재 크기가 충분하지 않을 때 생성해야 하는 새 연결 수입니다.
  • maxIdleTime: 연결이 사용되지 않고 풀에 남아 있을 수 있는 시간(초).
  • maxPoolSize: 풀에 머물 수 있는 최대 연결 수
  • minPoolSize: 언제든지 풀에 남아 있어야 하는 연결 개체의 최소 수입니다.

package com.journaldev.example;

/**
 * Java JDBC Connection pool using C3PO example program
 * 
 * @author pankaj
 */

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Demo {

	static ComboPooledDataSource comboPooledDataSource = null;

	static {
		comboPooledDataSource = new ComboPooledDataSource();

		comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
		comboPooledDataSource.setUser("root");
		comboPooledDataSource.setPassword("root");

		comboPooledDataSource.setMinPoolSize(3);
		comboPooledDataSource.setAcquireIncrement(3);
		comboPooledDataSource.setMaxPoolSize(30);

	}

public static void main(String[] args) throws SQLException {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = comboPooledDataSource.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery("select * from tblemployee");
			while (resultSet.next()) {
				System.out.println("empId:" + resultSet.getInt("empId"));
				System.out.println("empName:" + resultSet.getString("empName"));
				System.out.println("dob:" + resultSet.getDate("dob"));
				System.out.println("designation:" + resultSet.getString("designation"));
			}
		} finally {
			resultSet.close();
			statement.close();
			connection.close();
		}
	}

}

산출:

Aug 29, 2020 8:59:05 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge9kqacgbp7hjpftse6|77a567e1, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> null, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge9kqacgbp7hjpftse6|77a567e1, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/empdb?useSSL=false, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 30, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]

empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer

이것이 JDBC 연결 풀 예제 자습서의 전부입니다. 여기에서 중요한 내용이 누락되지 않았으면 합니다.

참조: C3P0