[+/-]
このセクションでは、複数の状況での Connector/J の使用方法を説明します。
このセクションでは、Connector/J の使用に関連する J2EE コンセプトの一般的な背景を説明します。
接続プーリングは、すべてのスレッドが必要な接続をすぐに使用できるよう、接続のプールを作成し管理する方法です。
接続をプールするこの方法は、ほとんどのアプリケーションは、普通数ミリ秒で完遂できるトランザクションを積極的に処理している時に、スレッドが JDBC 接続にアクセスすることだけを必要とするという事実に基づいています。トランザクションを処理していない時、接続はそうでなければ待機します。代わりに、接続プールは他のスレッドに、待機接続を有効に利用することを許可します。
実際には、スレッドが MySQL や、JDBC を使用する他のデータベースに対して作業を行う時、プールからの接続を要求します。スレッドは接続を使い終えたらそれをプールに戻し、他のスレッドが使用できるようにします。
接続がプールから貸し出されると、要求したスレッドが独占的にそれを使用します。プログラミングの観点からは、スレッドが
JDBC 接続が必要になるたびに
DriverManager.getConnection()
を呼び出すのと同じことですが、しかし接続プーリングを使えば、スレッドは新しい、または既存の接続を使用する可能性があります。
接続プーリングは、 全体的なリソースの使用を削減しつつ、Java アプリケーションの能率を著しく向上させます。接続プーリングの主な利点 :
接続作成時間の短縮
他のデータベースに比べ、 MySQL が提供する高速接続 setup に対してはこれはあまり関係ありませんが、新しい JDBC 接続の作成ではネットワーキングと JDBC ドライバのオーバヘッドが増えます。これは接続を再利用することで避けることができます。
簡略化されたプログラム モデル
接続プーリングを使用する場合、各スレッドは専用の JDBC 接続を作成したかのような動作が可能になり、直接的な JDBC プログラミング テクニックを使用することができるようになります。
制御されたリソースの使用
接続プーリングを使用せず、代わりにスレッドが接続を必要とするたびに新しいものを作成する場合、 アプリケーションのリソースの使用はきわめて無駄なものになり、荷重を受けて予想外の動作に出る可能性があります。
MySQL への各接続は、クライアント側とサーバ側両方にオーバヘッド ( メモリ 、CPU 、コンテキスト スイッチ、など ) を持つことを覚えておいてください。すべての接続は、アプリケーションと MySQL で利用できるリソースの数を制限します。これらのリソースの多くは、接続が有効な作業をしていなくてもかまわず使用されます !
リソースの利用を、ただ遅いだけでなく、アプリケーションが失効しかけるまで押さえながら、接続プールを有効にして最大限に機能させることができます。
幸運にも、Sun は JDBC の接続プーリングのコンセプトを、JDBC-2.0 Optional インターフェイスを通して標準化し、すべての主要なアプリケーション サーバは MySQL Connector/J と正常に機能するこれらの API を実装しています。
通常、接続プールはアプリケーション サーバの構成ファイルで構成し、Java Naming または Directory Interface (JNDI) を介してアクセスします。次のコードは、J2EE アプリケーション サーバで展開されたアプリケーションから、接続プールを使用する例を示しています :
例 24.11. J2EE アプリケーション サーバで接続プールを使用
import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import javax.naming.InitialContext; import javax.sql.DataSource; public class MyServletJspOrEjb { public void doSomething() throws Exception { /* * Create a JNDI Initial context to be able to * lookup the DataSource * * In production-level code, this should be cached as * an instance or static variable, as it can * be quite expensive to create a JNDI context. * * Note: This code only works when you are using servlets * or EJBs in a J2EE application server. If you are * using connection pooling in standalone Java code, you * will have to create/configure datasources using whatever * mechanisms your particular connection pooling library * provides. */ InitialContext ctx = new InitialContext(); /* * Lookup the DataSource, which will be backed by a pool * that the application server provides. DataSource instances * are also a good candidate for caching as an instance * variable, as JNDI lookups can be expensive as well. */ DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/MySQLDB"); /* * The following code is what would actually be in your * Servlet, JSP or EJB 'service' method...where you need * to work with a JDBC connection. */ Connection conn = null; Statement stmt = null; try { conn = ds.getConnection(); /* * Now, use normal JDBC programming to work with * MySQL, making sure to close each resource when you're * finished with it, which allows the connection pool * resources to be recovered as quickly as possible */ stmt = conn.createStatement(); stmt.execute("SOME SQL QUERY"); stmt.close(); stmt = null; conn.close(); conn = null; } finally { /* * close any jdbc instances here that weren't * explicitly closed during normal code path, so * that we don't 'leak' resources... */ if (stmt != null) { try { stmt.close(); } catch (sqlexception sqlex) { // ignore -- as we can't do anything about it here } stmt = null; } if (conn != null) { try { conn.close(); } catch (sqlexception sqlex) { // ignore -- as we can't do anything about it here } conn = null; } } } }
上記の例で示されているように、JNDI InitialContext を取得し、DataSource をルックアップした後では、残りのコードは、JDBC プログラミングの経験がある人には見覚えのあるものになります。
接続プーリングを使用する際の最も重要な注意点は、コードになにが起こっても ( 例えばフロー制御など ) 、接続とそれによって作成されたすべてのもの ( ステートメント もしくは 結果セット等 ) を必ず閉じることです。そうすると、それらを再使用することができますが、これを怠ればそれらは座礁してしまい、それらが表す MySQL サーバ リソース ( バッファ、ロック、もしくはソケットなど ) が、良い場合でもしばらくの間、ひどい時は永久に停滞する可能性があります。
接続プールの適切なサイズは?
構成におけるすべての経験則と同じく、答えは : 場合によって異なる。適したサイズは予測されたロードとデータベース トランザクション時間の平均によりますが、最適な接続プールのサイズは予想するより小さなものになります。Sun の Java Petstore ブループリント アプリケーションを例に挙げると、許容可能な応答時間での MySQL または Tomcat を使用して、15-20 接続の接続プールは比較的緩やかなロード ( 600 平行ユーザ ) をサーブすることができます。
アプリケーションへの接続プールのサイズを正しく計るには、Apache JMeter または The Grinder のようなロード テスト スクリプトを作成し、アプリケーションをロード テストしてください。
開始ポイントを判断する簡単な方法は、接続プールの接続の最大数を非有界なるよう構成し、ロード テストを実行、同時に使用された接続の最大数を計ります。そこから逆に作業して、プールされた接続の最小、または最大のどんな値が、特定のアプリケーションに最高の性能を与えるか判断することができます。
次の指示は Tomcat-5.x のインストラクションに基づいており、この資料が書かれた時の現行版だったものは http://jakarta.apache.org/tomcat/tomcat-5.0-doc/jndi-datasource-examples-howto.html で見ることができます。
まず、$CATALINA_HOME/common/lib
内の
Connector/J についてくる .jar
ファイルをインストールし、コンテナにインストールされたすべてのアプリケーションが利用できるようにします。
次に、ウェブ
アプリケーションを定義するコンテキストで、宣言リソースを
$CATALINA_HOME/conf/server.xml
に追加することにより、JNDI DataSource
を構築します :
<Context ....> ... <Resource name="jdbc/MySQLDB" auth="Container" type="javax.sql.DataSource"/> <!-- The name you used above, must match _exactly_ here! The connection pool will be bound into JNDI with the name "java:/comp/env/jdbc/MySQLDB" --> <ResourceParams name="jdbc/MySQLDB"> <parameter> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </parameter> <!-- Don't set this any higher than max_connections on your MySQL server, usually this should be a 10 or a few 10's of connections, not hundreds or thousands --> <parameter> <name>maxActive</name> <value>10</value> </parameter> <!-- You don't want to many idle connections hanging around if you can avoid it, only enough to soak up a spike in the load --> <parameter> <name>maxIdle</name> <value>5</value> </parameter> <!-- Don't use autoReconnect=true, it's going away eventually and it's a crutch for older connection pools that couldn't test connections. You need to decide whether your application is supposed to deal with SQLExceptions (hint, it should), and how much of a performance penalty you're willing to pay to ensure 'freshness' of the connection --> <parameter> <name>validationQuery</name> <value>SELECT 1</value> </parameter> <!-- The most conservative approach is to test connections before they're given to your application. For most applications this is okay, the query used above is very small and takes no real server resources to process, other than the time used to traverse the network. If you have a high-load application you'll need to rely on something else. --> <parameter> <name>testOnBorrow</name> <value>true</value> </parameter> <!-- Otherwise, or in addition to testOnBorrow, you can test while connections are sitting idle --> <parameter> <name>testWhileIdle</name> <value>true</value> </parameter> <!-- You have to set this value, otherwise even though you've asked connections to be tested while idle, the idle evicter thread will never run --> <parameter> <name>timeBetweenEvictionRunsMillis</name> <value>10000</value> </parameter> <!-- Don't allow connections to hang out idle too long, never longer than what wait_timeout is set to on the server...A few minutes or even fraction of a minute is sometimes okay here, it depends on your application and how much spikey load it will see --> <parameter> <name>minEvictableIdleTimeMillis</name> <value>60000</value> </parameter> <!-- Username and password used when connecting to MySQL --> <parameter> <name>username</name> <value>someuser</value> </parameter> <parameter> <name>password</name> <value>somepass</value> </parameter> <!-- Class name for the Connector/J driver --> <parameter> <name>driverClassName</name> <value>com.mysql.jdbc.Driver</value> </parameter> <!-- The JDBC connection url for connecting to MySQL, notice that if you want to pass any other MySQL-specific parameters you should pass them here in the URL, setting them using the parameter tags above will have no effect, you will also need to use & to separate parameter values as the ampersand is a reserved character in XML --> <parameter> <name>url</name> <value>jdbc:mysql://localhost:3306/test</value> </parameter> </ResourceParams> </Context>
通常は、Tomcat のデータソースを構成する方法は随時変化し、XML ファイルで間違ったシンタックスを使用している場合は残念ながら、以下に似た例外が投入される可能性が高いので、Tomcat のバージョンについてくるインストール インストラクションにしたがってください。
Error: java.sql.SQLException: Cannot load JDBC driver class 'null ' SQL state: null
このインストラクションは JBoss-4.x
をカバーしています。アプリケーション
サーバで JDBC ドライバ
クラスを利用可能にするには、Connector/J
についてくる .jar
ファイルを、サーバ構築のために、lib
ディレクトリにコピーします ( これは通常
default
と呼ばれる
)。そして、同じ構築ディレクトリで、deploy
と名付けられたサブディレクトリで、"-ds.xml"
で終わるデータソース
構築ファイルを作成します。"-ds.xml"
はこのファイルを JDBC Datasource
としてデプロイするよう JBoss
に指示します。ファイルには次の内容が含まれています
:
<datasources> <local-tx-datasource> <!-- This connection pool will be bound into JNDI with the name "java:/MySQLDB" --> <jndi-name>MySQLDB</jndi-name> <connection-url>jdbc:mysql://localhost:3306/dbname</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name>user</user-name> <password>pass</password> <min-pool-size>5</min-pool-size> <!-- Don't set this any higher than max_connections on your MySQL server, usually this should be a 10 or a few 10's of connections, not hundreds or thousands --> <max-pool-size>20</max-pool-size> <!-- Don't allow connections to hang out idle too long, never longer than what wait_timeout is set to on the server...A few minutes is usually okay here, it depends on your application and how much spikey load it will see --> <idle-timeout-minutes>5</idle-timeout-minutes> <!-- If you're using Connector/J 3.1.8 or newer, you can use our implementation of these to increase the robustness of the connection pool. --> <exception-sorter-class-name>com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter</exception-sorter-class-name> <valid-connection-checker-class-name>com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker</valid-connection-checker-class-name> </local-tx-datasource> </datasources>