Symfoware

Symfowareについての考察blog

Tomcat JDBC Connection Poolで通常のJavaプログラムからPostgreSQL 9.3に接続する

久しぶりにTomcatを触って知ったのですが、Tomcat 7.0.19以降は独自のコネクションプールを
同梱するようになっているんですね。

Commons DBCPを超えるTomcat JDBC Poolとは

勉強がてら、素のJavaから使ってみます。




サンプルプログラム



プログラムは、こちらのドキュメントを参考にしました。というかそのままです。
The Tomcat JDBC Connection Pool


今回は、PostgreSQL 9.3への接続をプーリングしてみようと思います。

実行に必要なjarファイルは、PostgreSQL JDBCドライバ
FreeBSD + PostgreSQL 9.3.2 にJavaで接続する
こちらでダウンロードした「postgresql-9.3-1100.jdbc4.jar」

Tomcat 7インストールディレクトリの
bin/tomcat-juli.jar
lib/tomcat-jdbc.jar

この3つになります。

384_01.png



lib/tomcat-dbcp.jarも必要かな?と思いましたが実行には不要のようでした。
また、tomcat-juli.jarが見つからないとこんなエラーが発生します。


Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory
at org.apache.tomcat.jdbc.pool.PoolProperties.<clinit>(PoolProperties.java:41)




サンプルプログラムはこんな感じになりました。


  1. import java.sql.Connection;
  2. import java.sql.ResultSet;
  3. import java.sql.Statement;
  4. import org.apache.tomcat.jdbc.pool.DataSource;
  5. import org.apache.tomcat.jdbc.pool.PoolProperties;
  6. public class PoolSample {
  7.     public static void main(String[] args) throws Exception {
  8.         PoolProperties p = new PoolProperties();
  9.         
  10.         // 接続情報の設定
  11.         p.setUrl("jdbc:postgresql://192.168.1.101:5432/sample");
  12.         p.setDriverClassName("org.postgresql.Driver");
  13.         p.setUsername("pgadmin");
  14.         p.setPassword("password");
  15.         
  16.         // その他オプション
  17.         p.setJmxEnabled(true);
  18.         p.setTestWhileIdle(false);
  19.         p.setTestOnBorrow(true);
  20.         p.setValidationQuery("SELECT 1");
  21.         p.setTestOnReturn(false);
  22.         p.setValidationInterval(30000);
  23.         p.setTimeBetweenEvictionRunsMillis(30000);
  24.         p.setMaxActive(100);
  25.         p.setInitialSize(10);
  26.         p.setMaxWait(10000);
  27.         p.setRemoveAbandonedTimeout(60);
  28.         p.setMinEvictableIdleTimeMillis(30000);
  29.         p.setMinIdle(10);
  30.         p.setLogAbandoned(true);
  31.         p.setRemoveAbandoned(true);
  32.         p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
  33.                 + "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
  34.         
  35.         
  36.         DataSource datasource = new DataSource();
  37.         datasource.setPoolProperties(p);
  38.         Connection con = null;
  39.         try {
  40.             con = datasource.getConnection();
  41.             Statement st = con.createStatement();
  42.             ResultSet rs = st.executeQuery("select * from test");
  43.             while (rs.next()) {
  44.                 System.out.println("Id:" + rs.getString("id") + " Name:" + rs.getString("name"));
  45.             }
  46.             rs.close();
  47.             st.close();
  48.         } finally {
  49.             if (con != null) {
  50.                 try {
  51.                     con.close();
  52.                 } catch (Exception ignore) {
  53.                 }
  54.             }
  55.         }
  56.     }
  57. }




実行してみると、ちゃんとデータベースに登録されている値が表示されます。






効果測定



コネクションをプールすることでほんとに速くなるのか、測定してみました。

まず、プーリングなし。


  1. import java.sql.Connection;
  2. import java.sql.DriverManager;
  3. public class NonPoolTime {
  4.     public static void main(String[] args) throws Exception {
  5.         
  6.         String url = "jdbc:postgresql://192.168.1.101:5432/sample";
  7.         String user = "pgadmin";
  8.         String pass = "password";
  9.         
  10.         long start = System.currentTimeMillis();
  11.         
  12.         for (int i = 0; i < 101; i++) {
  13.             
  14.             long lap = System.currentTimeMillis();
  15.             
  16.             Connection con = null;
  17.             try {
  18.                 con = DriverManager.getConnection(url, user, pass);
  19.             } finally {
  20.                 if (con != null) {
  21.                     try {
  22.                         con.close();
  23.                     } catch (Exception ignore) {
  24.                     }
  25.                 }
  26.             }
  27.             System.out.println(System.currentTimeMillis() - lap);
  28.         }
  29.         
  30.         long end = System.currentTimeMillis();
  31.         System.out.println(end - start);
  32.     }
  33. }





次にプーリングあり。


  1. import java.sql.Connection;
  2. import org.apache.tomcat.jdbc.pool.DataSource;
  3. import org.apache.tomcat.jdbc.pool.PoolProperties;
  4. public class PoolTime {
  5.     public static void main(String[] args) throws Exception {
  6.         PoolProperties p = new PoolProperties();
  7.         
  8.         // 接続情報の設定
  9.         p.setUrl("jdbc:postgresql://192.168.1.101:5432/sample");
  10.         p.setDriverClassName("org.postgresql.Driver");
  11.         p.setUsername("pgadmin");
  12.         p.setPassword("password");
  13.         
  14.         // その他オプション
  15.         p.setJmxEnabled(true);
  16.         p.setTestWhileIdle(false);
  17.         p.setTestOnBorrow(true);
  18.         p.setValidationQuery("SELECT 1");
  19.         p.setTestOnReturn(false);
  20.         p.setValidationInterval(30000);
  21.         p.setTimeBetweenEvictionRunsMillis(30000);
  22.         p.setMaxActive(100);
  23.         p.setInitialSize(10);
  24.         p.setMaxWait(10000);
  25.         p.setRemoveAbandonedTimeout(60);
  26.         p.setMinEvictableIdleTimeMillis(30000);
  27.         p.setMinIdle(10);
  28.         p.setLogAbandoned(true);
  29.         p.setRemoveAbandoned(true);
  30.         p.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
  31.                 + "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
  32.         
  33.         
  34.         DataSource datasource = new DataSource();
  35.         datasource.setPoolProperties(p);
  36.         
  37.         
  38.         long start = System.currentTimeMillis();
  39.         
  40.         for (int i = 0; i < 101; i++) {
  41.             
  42.             long lap = System.currentTimeMillis();
  43.             
  44.             Connection con = null;
  45.             try {
  46.                 con = datasource.getConnection();
  47.             } finally {
  48.                 if (con != null) {
  49.                     try {
  50.                         con.close();
  51.                     } catch (Exception ignore) {
  52.                     }
  53.                 }
  54.             }
  55.             
  56.             System.out.println(System.currentTimeMillis() - lap);
  57.         }
  58.         
  59.         long end = System.currentTimeMillis();
  60.         System.out.println(end - start);
  61.     }
  62. }




測定した結果はこうなりました。

パターンプールなしプールあり
初回接続93ms208ms
初回以降100回のコネクション作成の平均7.73ms0.25ms
処理時間トータル873ms233ms


言われてみればそうなのですが、初回の接続時間はプールしたほうが遅いです。
バッチ処理とか、コネクションを1回しか貼らないときは素の実装のほうがよさげ。

逆に頻繁にコネクションを作成する場合は、もちろんプールしたほうが結果的に速くなります。
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2014/03/22(土) 11:07:27|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<ライブラリに依存しないJavaプログラムでRedisにデータを登録、取得する(SET、GET) | ホーム | Tomcat 7のセッションをRedisに保存し、ロードバランスを行う>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1364-3ed1f41b
この記事にトラックバックする(FC2ブログユーザー)