- PR -

DataSourseの使い方

1
投稿者投稿内容
たけ
常連さん
会議室デビュー日: 2004/02/23
投稿数: 42
お住まい・勤務地: 神奈川県/東京都
投稿日時: 2005-11-02 13:47
お世話になります。

【環境】
Java1.5.0_03
Tomcat5.5.9
mysql-connector-java-3.1.10
RedHat9


DataSourceを使ってMySQLにアクセスしています。

データをDBに入れることはできたのですが、
どうも接続が開放されていないようです。

設定でremoveAbandoned、logAbandonedをtrueにしたところ、
以下のようなエラーメッセージが表示されていました。

 DBCP object created 2004-03-20 00:44:05 by the following code was never closed:
 java.lang.Exception
   at org.apache.commons.dbcp.AbandonedTrace.setStackTrace
     (AbandonedTrace.java:202)
   at org.apache.commons.dbcp.AbandonedObjectPool.borrowObject
     (AbandonedObjectPool.java:121)
   at org.apache.commons.dbcp.PoolingDataSource.getConnection
     (PoolingDataSource.java:140)
   at org.apache.commons.dbcp.BasicDataSource.getConnection
     (BasicDataSource.java:518)


一応Connectionをcloseしてはいるんですが、ダメなようです。
根本的に使い方が間違っているのでしょうか。

何かアドバイスをお願いいたします。


ソースは以下のようになっています。
===========================================================
public class DataSourceManager {
  // 取得したDataSourceを保持します。
  private static DataSource ds = null;

  /*
   * DataSourceを取得していなければDataSourceを取得し、
   * 呼び出したクラスに返します。
   */
  public static DataSource getDataSource() {
    if (ds == null) {
      // DataSourceを取得していない場合、DataSourceを取得します
      try {
        Context ctx = new InitialContext();
        ds = (DataSource)ctx.lookup("java:comp/env/jdbc/test");
      } catch (NamingException nex) {
        nex.printStackTrace();
      }
    }

    return ds;
  }
}


public class DataAccess {
  private DataSource ds = null;
  private Connection con = null;
  private Statement stmt = null;

  public void insertData(String _data) throws BatchUpdateException,Exception {
    String sql = "INSERT INTO test_table VALUES ('" + _data + "');";
    
    try {
      // DataSourceを取得します
      ds = DataSourceManager.getDataSource();
      // Connectionを取得します
      con = ds.getConnection();
      con.setAutoCommit(false);
      // Statementを取得します
      stmt = con.createStatement();

      // データをinsertします
      stmt.addBatch(sql);
      stmt.executeBatch();
      con.commit();
    } catch (BatchUpdateException buex) {
      throw new Exception(buex.getMessage());
    } catch (Exception ex) {
      throw new Exception(ex.getMessage());
    } finally {
      // リソースを開放します
      if (stmt != null) {
        stmt.close();
      }
      if (con != null) {
        con.close();
      }
    }
  }
}
===========================================================


[ メッセージ編集済み 編集者: たけ 編集日時 2005-11-02 13:48 ]

[ メッセージ編集済み 編集者: たけ 編集日時 2005-11-02 13:53 ]
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-11-02 17:17
引用:

コード:
  private DataSource ds = null;
  private Connection con = null;
  private Statement stmt = null;




DataAccessクラスがどのように利用されているものかわからないのですが、おそらくこれらが
インスタンス変数として宣言されているのが原因です。これらをすべてローカル変数にして
みてください。dsに関してはインスタンス変数でも動くでしょうが、ローカル変数にすべき
でしょうね。
たけ
常連さん
会議室デビュー日: 2004/02/23
投稿数: 42
お住まい・勤務地: 神奈川県/東京都
投稿日時: 2005-11-02 17:39
ukさん、アドバイスありがとうございます。

DataAccessクラスは他にもupdate、deleteなんかのメソッドも持っていて、
そっちでも使うのでインスタンス変数として宣言してしまいました。

これらをローカル変数として試してみます。
だい
会議室デビュー日: 2004/11/19
投稿数: 10
投稿日時: 2006-09-20 21:30
過去の内容に横やり入れるようで申し訳ないですが、こちらの質問は解決されたのでしょうか?
原因としては、con などの変数がインスタンス変数だったことなのでしょうか?

また、インスタンス変数でもCLOSE していれば問題ないかと思ってますが、インスタンス変数であってはならない理由を教えてください。

お願いします。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2006-09-22 11:58
引用:

だいさんの書き込み (2006-09-20 21:30) より:
また、インスタンス変数でもCLOSE していれば問題ないかと思ってますが、インスタンス変数であってはならない理由を教えてください。


回答にも「DataAccessクラスがどのように使われているかがわからない」と書きました
が、DataAccessクラスのインスタンスが複数のスレッドで共有されないようになって
いるのであれば、問題ありません。問題が発生したということは、おそらく共有される
つくりになっていたのでしょう。

ですが、そうでなくてもこのコードであればインスタンス変数である必要はまったく
ないので、ローカル変数にすべきです。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-09-22 13:10
引用:

ukさんの書き込み (2006-09-22 11:58) より:
ですが、そうでなくてもこのコードであればインスタンス変数である必要はまったく
ないので、ローカル変数にすべきです。



便乗質問ですが、lookupのコストは無視できる程度のものなのでしょうか。
その一点だけ気にかかったのですが。
計測したことはないですが、なんとなくlookupって重いイメージがあって…。
キャッシュしたくなる理由はそれに尽きるのですけどね。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2006-09-22 14:26
引用:

nagiseさんの書き込み (2006-09-22 13:10) より:
便乗質問ですが、lookupのコストは無視できる程度のものなのでしょうか。
その一点だけ気にかかったのですが。
計測したことはないですが、なんとなくlookupって重いイメージがあって…。
キャッシュしたくなる理由はそれに尽きるのですけどね。


lookupのコストは実装やアクセス頻度にもよるでしょうが、無視できないレベルだと
は思います。ServiceLocatorパターンが適用されるのもlookupのオーバヘッド回避の
ためという側面がありますし。

ただし、件のコードについてはDataAccessクラスの変数をローカル変数にしてもlookup
の回数は増えないので問題ありません。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-09-22 15:07
引用:

ukさんの書き込み (2006-09-22 14:26) より:
lookupのコストは実装やアクセス頻度にもよるでしょうが、無視できないレベルだと
は思います。ServiceLocatorパターンが適用されるのもlookupのオーバヘッド回避の
ためという側面がありますし。

ただし、件のコードについてはDataAccessクラスの変数をローカル変数にしてもlookup
の回数は増えないので問題ありません。



あぁ、私の見落としてでした。
ローカル変数が〜というのは件のソースのDataSourceManagerクラス側ではなく、
DataAccessクラス側の話だったのですね。
確かにここはローカル変数を使うべきところですね。

DataSourceManager側でキャッシュするのは問題ないわけですね。
すっきりしました。
1

スキルアップ/キャリアアップ(JOB@IT)