JavaでのTomcatデータソースJNDIの例
TomcatのDataSource JNDIの例チュートリアルへようこそ。前のチュートリアルではJDBC DataSourceを見て、それをスタンドアロンのJavaアプリケーションで使う方法を学びました。
トムキャットのデータソースJNDI
DataSourceをJNDIコンテキストと一緒に使用することで、実際の利点が得られます。たとえば、サーブレットコンテナに展開されたWebアプリケーションの接続プールの場合です。多くの人気のあるサーブレットコンテナは、リソースの設定とJNDIコンテキストを介してDataSourceの組み込みサポートを提供しています。これによって、わずかな構成行数でDataSource接続プールを作成して使用することができます。このチュートリアルは、Tomcat DataSourceのJNDI設定例を提供することを目的としています。Apache Tomcatでは、JNDIコンテキストでDataSourceを設定するための3つの方法が提供されています。
-
- アプリケーションのcontext.xml – これはDataSourceを設定する最も簡単な方法であり、必要なのはMETA-INFディレクトリにあるcontext.xmlファイルだけです。contextファイルにResource要素を定義し、コンテナが読み込みと設定を担当します。この方法は簡単ですが、いくつかの欠点があります。
contextファイルはWARファイルにバンドルされているため、小さな設定変更のたびに新しいWARをビルドして展開する必要があります。アプリケーションが分散環境で動作する場合や、テスト環境(例:QA、IT、PRODなど)に展開する必要がある場合も同じ問題が発生します。
データソースはアプリケーションの使用のためにコンテナによって作成されるため、グローバルに使用することはできません。データソースを複数のアプリケーションで共有することはできません。
同じ名前で定義されたグローバルデータソース(server.xml)がある場合、アプリケーションのデータソースは無視されます。
サーバのcontext.xml – サーバに複数のアプリケーションがあり、それらの間でDataSourceを共有したい場合、サーバのcontext.xmlファイルにそれを定義することができます。このファイルはapache-tomcat/confディレクトリにあります。server context.xmlファイルの範囲はアプリケーションです。したがって、100の接続を持つデータソースの接続プールを定義し、20のアプリケーションがある場合、データソースは各アプリケーションごとに作成されます。これにより、データベースサーバのリソースをすべて消費し、アプリケーションのパフォーマンスに悪影響を及ぼします。
server.xmlとcontext.xml – グローバルレベルでDataSourceを定義するために、server.xmlのGlobalNamingResources要素にそれらを定義することができます。このアプローチを使用する場合は、serverまたはアプリケーション固有のcontext xmlファイルからResourceLinkを定義する必要があります。これは、サーバ上で実行されている複数のアプリケーション間で共有する共通のリソースプールを共有する場合に適した方法です。リソースリンクをserverレベルのcontext xmlファイルまたはアプリケーションレベルのcontext xmlファイルに定義するかは、要件によります。
JavaウェブアプリケーションでのTomcat DataSource JNDIの例に移りましょう。テストデータのセットアップについては、JDBC DataSourceの例に関連する私の最後の記事を参照してください。
TomcatのDataSource JNDI設定例 – server.xml
以下のコードをtomcatのserver.xmlファイルに追加してください。コードはGlobalNamingResources要素に追加される必要があります。また、データベースのドライバーがtomcatのlibディレクトリに存在していることも確認してください。この場合、mysqlのjdbc jarがtomcatのlibに存在している必要があります。
<Resource name="jdbc/MyDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/UserDB"
username="scdev"
password="scdev123"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
ここでは、DataSourceの一種であるjdbc/MyDBという名前でJNDIコンテキストを作成しています。url、username、password、driverClassName属性にはデータベースの設定を渡しています。コネクションプーリングのプロパティは、maxActive、maxIdle、minIdle属性で定義されています。
TomcatのDataSource JNDIリソースリンクの設定 – context.xml
サーバーのcontext.xmlファイルに以下のコードを追加してください。
<ResourceLink name="jdbc/MyLocalDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource" />
リソースリンク名がグローバルリンクと異なることに注意してください。DataSourceを取得するために、Javaプログラムでこの名前を使用する必要があります。
「TomcatのDataSource JNDIの例」
JDBCDataSourceTomcatという名前のダイナミックなウェブアプリケーションを作成し、以下のコードでServletを作成してください。
package com.scdev.jdbc.datasource;
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.naming.NamingException;
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;
@WebServlet("/JDBCDataSourceExample")
public class JDBCDataSourceExample extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Context ctx = null;
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try{
ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select empid, name from Employee");
PrintWriter out = response.getWriter();
response.setContentType("text/html");
out.print("<html><body><h2>Employee Details</h2>");
out.print("<table border=\"1\" cellspacing=10 cellpadding=5>");
out.print("<th>Employee ID</th>");
out.print("<th>Employee Name</th>");
while(rs.next())
{
out.print("<tr>");
out.print("<td>" + rs.getInt("empid") + "</td>");
out.print("<td>" + rs.getString("name") + "</td>");
out.print("</tr>");
}
out.print("</table></body><br/>");
//lets print some DB information
out.print("<h3>Database Details</h3>");
out.print("Database Product: "+con.getMetaData().getDatabaseProductName()+"<br/>");
out.print("Database Driver: "+con.getMetaData().getDriverName());
out.print("</html>");
}catch(NamingException e){
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
rs.close();
stmt.close();
con.close();
ctx.close();
} catch (SQLException e) {
System.out.println("Exception in closing DB resources");
} catch (NamingException e) {
System.out.println("Exception in closing Context");
}
}
}
}
Servlet 3のアノテーションベースの設定を使用していることに注意してください。これはTomcat 7以降のバージョンで動作します。もしTomcatのバージョンが低い場合は、サーブレットのコードにいくつかの修正を行い、WebServletのアノテーションを削除し、web.xmlファイルで設定する必要があります。私たちが興味を持っているサーブレットのコード部分です。
ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
アプリケーションで使用するために JNDI リソースを定義する方法です。同様に以下のようにも記述することができました。
ctx = new InitialContext();
Context initCtx = (Context) ctx.lookup("java:/comp/env");
DataSource ds = (DataSource) initCtx.lookup("jdbc/MyLocalDB");
私は、接続しているデータベースを確認するために、いくつかのデータベース情報も印刷しています。今、アプリケーションを実行すると、以下の出力が表示されます。Tomcatのデータソースを使用しているので、データベースサーバーを簡単に切り替えることができるかどうか見てみましょう。必要なのはデータベースのプロパティを変更するだけです。Oracleデータベースに切り替える場合、私のリソース設定は以下のようになります。
<Resource name="jdbc/MyDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:orcl"
username="hr"
password="oracle"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
そして、サーバーを再起動し、アプリケーションを実行すると、Oracleデータベースに接続し、以下の結果が生成されます。これで、TomcatのDataSource JNDI構成のチュートリアルは以上です。context.xmlファイルでも同じようにリソースを定義することができます。