データソースをインスタンス化するメインコントローラーサーブレットがあります。サーブレットは接続を開いたり閉じたりします。主に、サーブレットは「ファクトリパターン」を使用してアプリケーションからコマンドをインスタンス化します。説明するコードは次のとおりです。
public void init() throws ServletException {
super.init();
try {
datasource =(DataSource) getServletContext().getAttribute("DBCPool");
}
catch (Exception e) {
}
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//some code...
Connection connection = null;
if(cmd.mightNeedLazyLoadingAConnection)
{
connection = null;
}
else
connection = getConnection();//where getConnection is a method: datasource.getconnection();
//now a command (a java class) is instantied, to which the "null" CONNECTION obj is passed as parameter
cmdFactory.getInstance().getCommand(Cmd).execute(tsk,connection);
//some code
//Then wherever there is catch exception i close() the connection
// and it is always closed in finally
finally {
if(connection!=null)
connection.close()
}
}
さて、これは最初のケース、つまりconnection = nullの場合に問題があります。これは、 「finally」部分で接続が閉じられないためです(理由は以下のUpdateで説明されています)。
「connection=null」は、コマンドが探しているデータがIDマップにキャッシュされているために、コマンドがデータベース接続を開く必要がない場合に使用します。
.execute(tsk、connection);で"Connection" objを"null"パラメーターとして渡そうとしまし た。次に、対応するJavaクラスで、必要に応じて接続を開きます
->コマンド内で接続を開きましたが、プロセスがサーブレットに戻ると、「接続」はnullであるため、閉じられていません。 「Connection」 objの値を更新して、サーブレットに戻ったときに「Null」ではなくなり、閉じることができるようにするにはどうすればよいですか
。
私は通常、 db接続を開閉するコントローラーサーブレットを使用することを好みます。そのため、プールからdb接続を「遅延読み込み」する必要があるこの種のシナリオに対処するための最良の方法は何でしょうか。サーブレットに割り当てられたdb接続
のオープン/クローズを維持しますか?
更新(さらに説明するため):
- 私がコマンドを持っていると言う:X.java
- このコマンドは、db接続を必要としない場合があります(検索されたデータがIDマップにあるかどうかによって異なります)
私が欲しいシステムは次のとおりです。
(1)「クライアントリクエスト」
(2)---> "サーブレット": command.execute(connection)//ここでconnection=null今のところ
(3)---> 「コマンドX」:データベースに移動する必要がありますか、それともレコードがIDマップにありますか?
(3.a)データベースに移動する必要がある場合:
(3.a.1)connection = datasource.getconnection
(3.a.2)データを取得します
(4)--->サーブレットに戻る:「サーブレット」の「接続」を閉じる
現在は(3.a.2)まで機能していますが、(4)に戻ると、接続はまだ「null」であるため、コードは次のようになります。
finally {
if(connection!=null)
connection.close()
}
動作しない(接続を閉じない)ため、dbプールはそのように排出されます。「null」で始まり、コマンド「X」内で変更される接続は、コマンド「X」のスコープ内で「更新」されるだけでなく、「globaly」を新しい値に更新するにはどうすればよいでしょうか。
ソリューション
同じシナリオが発生した場合は、次の2つのソリューションから選択できます。
@Ryan Stewartが「クリーンな抽象化」とより専門的なソリューションについて言及しているように、LazyConnectionDataSourceProxyを使用することもできます。
または、以下で説明する私のソリューションを使用したい場合(基本的に、「LazyConnectionDataSourceProxy」に似たクラスを実装しましたが、それほどクリーンではなく、「LazyConnectionDataSourceProxy」よりも詳細の抽象化が少なくなっています)
私の個人的な解決策、詳細:
- 「Helper」クラスを作成しました。このクラスは、「datasource」をパラメーターとして受け取ります。
- このヘルパークラスには、次のメソッドがあります。プールからの「レイジーゲット」接続、「クローズ」接続
- このクラスはサーブレットでインスタンス化され、アプリケーション全体で必要な場合にのみプールから接続を取得します。
これは、サーブレットで追加/変更したコードです。
Connection connection = null;
if(cmd.mightNeedLazyLoadingAConnection)
{
helper hp = new helper(datasource);
cmdFactory.getInstance().getCommand(Cmd).execute(tsk,hp);
}
else
{
connection = getConnection();
cmdFactory.getInstance().getCommand(Cmd).execute(tsk,connection);
}
次に、コマンド「X」で、db接続が必要だと言います。
Connection connection = hp.LazyGet();//Now got a connection from the pool
このようにして、プロセスフローがサーブレットレベルに戻ったときに、次のことができます。
- 選ぶ
- ロールバック
- 専念
- 等..
ヘルパークラスのこのhpオブジェクトのすべて。
これからどのようなメリットがありますか:
- すべてのデータベースのオープン/クローズ/コミット/ロールバックを1つの場所、つまりコマンドの実行を担当するサーブレットに制限します。
- 3つのケースがあります: dbを必要としない/常にdbを必要とする/ dbを必要とする可能性があるため、データベースへの呼び出しを1/3に減らしました。これは、データベースの呼び出しが新機能と新しいユーザー登録によって指数関数的に増加することをよく知っています。
これは最もクリーンな回避策ではないかもしれませんが、この方法と追加の「不要な」1/3データベース呼び出しがある場合は、確かに優れています。または、テスト済みの抽象的でクリーンなメソッドが必要な場合は、LazyConnectionDataSourceProxyを使用します。