Javaにおけるコネクションプーリング

コネクションプーリングとは、コネクションオブジェクトのプールです。コネクションプーリングは、オブジェクトプールのデザインパターンに基づいています。オブジェクトプーリングのデザインパターンは、新しいオブジェクトを作成するコスト(時間やCPU、ネットワーク、入出力などのリソース)が高い場合に使用されます。オブジェクトプーリングのデザインパターンによれば、アプリケーションは事前にオブジェクトを作成し、プールまたはコンテナに配置します。アプリケーションがそのようなオブジェクトを必要とする場合は、新しいオブジェクトを作成するのではなく、プールから取得します。

コネクションプーリング戦略を使用するアプリケーションは、再利用可能なDB接続オブジェクトを持っています。そのため、データベースとのやり取りが必要な場合、アプリケーションはプールから接続インスタンスを取得します。コネクションプーリングは、データベースとのやり取りを行うアプリケーションのパフォーマンスを向上させます。

Connection Pooling

私たちは自分自身で接続プールの実装を作成することができます。どんな接続プールフレームワークでも、3つのタスクを実行する必要があります。

  • Creating Connection Objects
  • Manage usage of created Objects and validate them
  • Release/Destroy Objects

Javaでは、使用できる便利なライブラリのセットがあります。それらを使用するには、わずかなプロパティの設定が必要です。

Javaアプリケーションにおける接続プーリング

以下の図書館を見てみましょう。 (Ika no toshokan o mite mimashou.)

  • Apache Commons DBCP 2
  • HikariCP
  • 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を開きます。

「ファイル」メニューをクリックし、新規作成 -> Mavenプロジェクトを選択します。

以下の画面が表示されます。シンプルなプロジェクトの作成オプションを選択し、次へボタンをクリックしてください。

New Maven Project
    グループID、アーティファクトID、名前、説明を入力してください。
Maven Project Configs

終了ボタンをクリックしてください。

    MySQLのために、次の依存関係をpom.xmlに追加してください。
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.49</version>
</dependency>
    プロジェクトを右クリックし、Mavenを選択してプロジェクトを更新し、OKをクリックしてください。これにより、すべての依存関係がダウンロードされます。

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の2つのタイプ(BasicDataSourceとPoolingDataSource)を提供しています。

BasicDataSourceとは、その名前の通り、シンプルであり、一般的な用途に適しています。内部的には、自動的にプーリングされたデータソースが作成されます。

以下の手順を見て、コネクションプールを初期化しましょう。

    1. BasicDataSourceのインスタンスを作成する

 

    1. JDBC URL、データベースのユーザー名とパスワードを指定する

 

    1. アイドル接続の最小数を指定する(常にプール内に残る必要がある接続の最小数)

 

    1. アイドル接続の最大数を指定する(プール内のアイドル接続の最大数)

 

    最大接続数の総数を指定する
package com.scdev.example;

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

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 のインスタンスを作成します。

 

    1. ステップ1で作成した ConnectionFactory のインスタンスを使用して PoolableConnectionFactory のインスタンスを作成します。

 

    1. GenericObjectPoolConfig のインスタンスを作成し、最大アイドル、最小アイドル、最大接続のプロパティを設定します。

 

    1. ステップ2とステップ3で作成したインスタンスを使用して ObjectPool を初期化します。

 

    1. PoolableConnectionFactory のインスタンスとしてプールを設定します。

 

    最後に、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は高速で信頼性があり、シンプルなconnection poolingのためのソリューションの一つです。Spring Boot 2.xなどのフレームワークは、デフォルトのconnection managerとして使用しています。

私たちのプロジェクトのpom.xmlに以下の依存関係を追加して、HikariCPを使用してください。

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

HikariCP の設定:

以下の例プログラムで示されているように、Javaベースの設定を使用するか、プロパティファイルを使用してHikariCPを設定することができます。以下のプロパティを見てみましょう。

  • idleTimeout: Time in milliseconds for which connection object can stay in the pool as idle. It works with minimumIdle and maximumPoolSize properties. After a specified time connection object will be released.
  • connectionTimeout: Time in milliseconds for which the client will wait for connection object from Pool. If the time limit is reached then SQL Exception will be thrown.
  • autoCommit: We can specify true or false and if it is set to true then it will automatically commit every SQL statements you execute and if it is set to false then we need to commit SQL statements manually
  • cachePrepStmts: Enable caching for Prepare Statement
  • minimumIdle: Minimum number of connection objects needs to remain in the pool at any time.
  • maximumPoolSize: Maximum number of connections that can stay in the pool.
package com.scdev.example;

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

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: Preferred Jdbc Driver
  • jdbcUrl: JDBC Url for the database.
  • initialPoolSize: Number of connections created in the pool at startup.
  • acquireIncrement: Number of new connections needs to be created when the current size is not enough.
  • maxIdleTime: Number of seconds Connection can remain in Pool without being used.
  • maxPoolSize: Maximum number of connections that can stay in Pool.
  • minPoolSize: Minimum number of connection objects needs to remain in Pool at any time.
package com.scdev.example;

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

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コネクションプールの例チュートリアルは以上です。何か重要な点が抜けていないことを願っています。

参考文献:HikariCP、Apache Commons DBCP、C3P0

コメントを残す 0

Your email address will not be published. Required fields are marked *