- - PR -
DataSourseの使い方
1
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 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 ] | ||||||||
|
投稿日時: 2005-11-02 17:17
DataAccessクラスがどのように利用されているものかわからないのですが、おそらくこれらが インスタンス変数として宣言されているのが原因です。これらをすべてローカル変数にして みてください。dsに関してはインスタンス変数でも動くでしょうが、ローカル変数にすべき でしょうね。 | ||||||||
|
投稿日時: 2005-11-02 17:39
ukさん、アドバイスありがとうございます。
DataAccessクラスは他にもupdate、deleteなんかのメソッドも持っていて、 そっちでも使うのでインスタンス変数として宣言してしまいました。 これらをローカル変数として試してみます。 | ||||||||
|
投稿日時: 2006-09-20 21:30
過去の内容に横やり入れるようで申し訳ないですが、こちらの質問は解決されたのでしょうか?
原因としては、con などの変数がインスタンス変数だったことなのでしょうか? また、インスタンス変数でもCLOSE していれば問題ないかと思ってますが、インスタンス変数であってはならない理由を教えてください。 お願いします。 | ||||||||
|
投稿日時: 2006-09-22 11:58
回答にも「DataAccessクラスがどのように使われているかがわからない」と書きました が、DataAccessクラスのインスタンスが複数のスレッドで共有されないようになって いるのであれば、問題ありません。問題が発生したということは、おそらく共有される つくりになっていたのでしょう。 ですが、そうでなくてもこのコードであればインスタンス変数である必要はまったく ないので、ローカル変数にすべきです。 | ||||||||
|
投稿日時: 2006-09-22 13:10
便乗質問ですが、lookupのコストは無視できる程度のものなのでしょうか。 その一点だけ気にかかったのですが。 計測したことはないですが、なんとなくlookupって重いイメージがあって…。 キャッシュしたくなる理由はそれに尽きるのですけどね。 | ||||||||
|
投稿日時: 2006-09-22 14:26
lookupのコストは実装やアクセス頻度にもよるでしょうが、無視できないレベルだと は思います。ServiceLocatorパターンが適用されるのもlookupのオーバヘッド回避の ためという側面がありますし。 ただし、件のコードについてはDataAccessクラスの変数をローカル変数にしてもlookup の回数は増えないので問題ありません。 | ||||||||
|
投稿日時: 2006-09-22 15:07
あぁ、私の見落としてでした。 ローカル変数が〜というのは件のソースのDataSourceManagerクラス側ではなく、 DataAccessクラス側の話だったのですね。 確かにここはローカル変数を使うべきところですね。 DataSourceManager側でキャッシュするのは問題ないわけですね。 すっきりしました。 |
1