検索

キーワード


【Java】Webアプリケーションでのコネクションプーリング

  • 公開日:2020-10-30 11:59:08
  • 最終更新日:2020-11-17 18:24:32

こんにちは。エンジニアの新田です!

ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。

今回は、Webアプリケーションからのデータベース接続とコネクションプーリングについて説明します。

Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!

関連記事:【Java】JDBCとは? 【データベース】PostgreSQLをWindowsにインストール 【データベース】データベースとテーブルの作成(PostgreSQL) 【Java】Webアプリケーションからデータベースへの接続


コネクションプーリングとは?

コネクションプーリングとは、プログラムがデータベース(DBMS)へアクセスする際、アクセス要求のたびに接続や切断を繰り返すのではなく、一度確立したDB接続(コネクション)を維持して使い回す手法です。

データベースに対して外部のアプリケーションからアクセス(読み書き)する場合、データベースに対して処理を依頼する必要がありますが、そのためには処理を依頼して結果を受信するためのコネクション(connection)を確立する必要があります。

このコネクションの確立や切断を行うたびに一定のオーバヘッド(処理負荷、間接的な処理時間)が生じるため、頻繁にアクセスが行われるシステムでは性能劣化の原因となってしまう場合があります。

コネクションプーリングを使うと、一度確立したコネクションを使用後に切断せず、コネクションプールと呼ばれる場所で保持します。次にDBアクセスの要求があったときに保持していたコネクションを再利用する事で接続と切断のオーバーヘッドが発生しません。

コネクションプールに保持されるコネクション数には上限を設定する事ができ、保持されているコネクション数が設定された上限数に達した場合は、それ以上コネクションは作られずにプールに保持されているコネクションのみを使用します。

このようにデータベースへのコネクションを使い回すことで、同時多数のアクセスが想定されるWebアプリケーションなどではコネクションが増えすぎてリソース不足に陥る事をコントロールできます。ただし、プールされたコネクションもメモリ容量などのリソースを占有(データベース側も含む)するため、用途や使用環境によって適切な設定値に調整する必要があります。


アプリケーションからデータベースへの接続

通常、アプリケーションからデータベースの情報を利用する場合は以下のような手順が必要です。

  1. ネットワークコネクションの確立
  2. 接続ユーザの認証
  3. データベースコネクションの確立
  4. SQLクエリの発行
  5. SQLクエリの処理
  6. SQLクエリの結果取得
  7. データベースコネクションの切断
  8. ネットワークコネクションの切断
参考記事:【Java】Webアプリケーションからデータベースへの接続


この様にデータベース接続には様々な手順が必要です。

Webへのアクセスが発生する毎にこの手順を繰り返すのは非常に効率が悪くなります。1度のアクセスでは1秒未満の処理時間かもしれませんが、多くのWebアプリケーションでは同時多数のアクセスが発生するため、1アクセスのオーバヘッドが数ミリ秒であってもアクセスが重なればレスポンスタイムに大きな影響を与えます。

コネクションプールを使用する事で、1~3 、7~8 の処理が不要になり、データベースを使った処理の効率が良くなり、Webアクセスでのレスポンス向上も見込めます。


通常のデータベース接続

通常のデータベース接続のイメージ



コネクションプーリングを利用したデータベース接続

コネクションプーリングを利用したデータベース接続のイメージ




コネクションプーリングの設定方法

コネクションプーリングの基本的な設定方法を紹介します。

ここで触れている設定項目以外にも様々な設定項目が存在しますが、この記事では基本的な設定項目のみ紹介します。


環境情報

OS:Windows

IDE:eclipse(動的Webプロジェクト)

DB:PostgreSQL 10(関連記事:【データベース】PostgreSQLをWindowsにインストール

実行環境:java8, tomcat8



server.xmlの設定

server.xmlは、Tomcatのメインの設定ファイルであり、Tomcat起動時に読み込まれています。

このファイルにコネクションプーリング用の設定を追加します。


eclipseの「動的Webプロジェクト」を作成すると、server.xmlに以下の要素が作成されます。

例:プロジェクト名「webtest」で作成した場合

<Context docBase="webtest" path="/webtest" reloadable="false" source="org.eclipse.jst.jee.server:webtest" />


この要素に対して、コネクションプーリング用に以下の設定を追加します。

<Context docBase="webtest" path="/webtest" reloadable="false" source="org.eclipse.jst.jee.server:webtest">
  <Resource
    name="jdbc/postgresql"
    type="javax.sql.DataSource"
    auth="Container"
    driverClassName="org.postgresql.Driver"
    url="jdbc:postgresql://localhost:5432/devdb01"
    username="devuser01"
    password="devuser01"
    maxActive="20"
    maxIdel="10"
    maxWait="10000"
  />
</Context>


各要素の説明

name:データソース名。この名前を使ってプログラムから指定する。

type:JNDIリソースのクラス型、インタフェース型を指定。

auth:リソースマネージャに接続する主体。Tomcatコンテナが接続する場合は「Container」を指定。

driverClassName:JDBCドライバクラス名

url:JDBC接続URL文字列

username:データベース接続ユーザ名

password:データベース接続パスワード

maxActive:同時に利用できるConnectionの数を指定。この数を超えた場合はConnectionが空くまで待機。

maxWait:Connectionの利用を待つ時間を指定。単位はミリ秒。

maxIdle:Connectionの利用がない状態で、いくつのConnectionを保持するか設定する。




サーブレットからの接続(javaコード)

サーブレットからのDB接続で、コネクションプールからコネクションを取得する例です。

関連記事:【Java】Webアプリケーションからデータベースへの接続 のサンプルコードに対して変更を行い、コネクションプールから接続を取得するように変更しています。


import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class DBConnectPoolSample extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException
	{
		Connection conn = null;

		response.setContentType("text/html; charset=Windows-31J");
		PrintWriter out = response.getWriter();
		out.println("<html><head></head><body>");
		out.println("<table border=’true’>");
		out.println("<tr><th>id</th><th>氏名</th><th>年齢</th><th>メールアドレス</th></tr>");

		try {
/*			// 通常のデータベース接続
			Class.forName("org.postgresql.Driver"); // JDBC ドライバの登録
			String url = "jdbc:postgresql://localhost:5432/devdb01"; // 接続先URL
			String user = "devuser01"; //ユーザ名
			String password = "devuser01"; // パスワード

			conn = DriverManager.getConnection(url, user, password); // 接続の確立
*/

			// コネクションプールを使ったデータベース接続
			Context context = new InitialContext();
			DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/postgresql");
			conn = ds.getConnection();

			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("SELECT * FROM member"); // SQL の送信

			while (rs.next()) {
				out.print("<tr>");
				out.print("<td>"+rs.getString("id")+"</td>");
				out.print("<td>"+rs.getString("name") + "</td>");
				out.print("<td>"+rs.getString("age") + "</td>");
				out.print("<td>"+rs.getString("email") + "</td>");
				out.print("</tr>");
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			out.println("クラスが見つかりません。");
		}
		finally {
			try {
				if (conn != null)
					conn.close(); // 接続の切断
			}
			catch (SQLException e) {}
		}

		out.println("</table>");
		out.println("</body></html>");
		out.close();
	}
}


変更したのは黄色の網掛け部分のみです。

server.xmlでデータベース接続設定を定義しているので、プログラム側では対象のデータソースを読み込むだけです。


getConnection() 実行時に、プールに存在するコネクションの状態で以下の何れかの処理が行われます。

  • 有効なコネクションが存在しない ⇒ 新規の接続を確立してコネクションを返す
  • 有効なコネクションが存在して利用可能 ⇒ 利用可能なコネクションを返す
  • 有効なコネクションが存在するが利用不可(空き無し) ⇒ 利用可能になるのを待つ(maxWaitを超えた場合はタイムアウトエラー)


実行結果

コネクションプールを使ったサンプルコードの実行結果

変更前と同じ結果を取得する事ができました。







関連記事:【Java】JDBCとは? 【データベース】PostgreSQLをWindowsにインストール 【データベース】データベースとテーブルの作成(PostgreSQL) 【Java】Webアプリケーションからデータベースへの接続



【著者】

新田

JavaメインのWebアプリケーション開発に多く携わっています。
Javaの基本的な部分の紹介や、これまで経験したシステム開発手法、新しい技術についても紹介していこうと思います。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様