1

JavaWeblogicポータルアプリケーションの特定の詳細をOracleDBに記録するために、データベースロギングを実装しました。このために、接続プールを使用して接続を取得し、それを使用してストアドプロシージャへのjdbc呼び出しを行います。

接続オブジェクトを取得してSPを呼び出す静的JavaメソッドlogServiceがあります。このlogserviceメソッドは、Javaアプリケーションのさまざまな場所から呼び出され、関連する詳細がパラメーターに渡され、パラメーターがSP呼び出しに渡されます。

したがって、ポータルにアクセスするユーザーごとに、約10〜20のlogserviceメソッド呼び出しがあります。したがって、10〜20のSP呼び出しを行い、SPを呼び出すたびにコミットする必要がありました。

しかし、問題は、コミット頻度が高いため、私のDBAは、トランザクションごとにコミットせず、一度に10〜20個のトランザクションすべてをコミットすることを推奨していることです。どうすればこれを達成できますか?明確でない場合は、サンプルコードを投稿できます。

はい、次のようにWebアプリケーション用のフィルターを既に使用しています。

public final class RequestFilter implements Filter{

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
 try {
      ((HttpServletResponse) response).sendRedirect(redirectUrl);

  if (chain != null) {
            chain.doFilter(request, response);
        }
     }
 finally { // commit transaction here }
 }
}

redirectURLにリダイレクトした後、次のようにアプリケーションの多くの場所からlogserviceを呼び出しています。

DBLog.logService(param1, param2); // static method call

このログサービスは、接続プールオブジェクトを使用してSPへのprepareCallを実行します。以下に、私が行っている方法の簡単なサンプルコードを示します。

public static void logService(String param1, String param2) {

try {

con=getConnection();
stmt = con.prepareCall("{call DB_LOG_SP (?, ?}");
stmt.setString(1, param1);
stmt.setString(2, param2);
stmt.execute();
stmt.close();
}finally {
           stmt.close();
           con.close();
        } 
 }

しかし、SP呼び出しの後に接続を閉じているので、doFilterメソッド内のfinally {}ブロックでトランザクションをコミットするにはどうすればよいですか?

フィルターアプローチ-

public class DBLog {

static Connection con = null;
    static PreparedStatement stmt = null;

static {
        try{
        new net.verizon.whatsnext.dblog.JDCConnectionDriver("oracle.jdbc.driver.OracleDriver", 
        "jdbc:oracle:thin:@localhost:7001:xe","user", "password"); 
    con=getConnection(); // Getting connection from Connection pool

    }catch(Exception e){}
    }

 public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:jdc:jdcpool"); 
    }


public static void logService(String param1, String param2) {
    ...
    finally {
               stmt.close();
            } 
     }

 public static void closeTrans() {

    con.commit();
    con.close();
    }
} //End of DBLog class


 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
    ...
     finally { 
          DBLog.closeTrans();
         }
    }

そのため、doFilterメソッドのfinallyブロックでコミットした後、finallyに接続を閉じています。私は正しくやっていますか?それは機能しますか?

4

3 に答える 3

1

セキュリティとロギングの場合のように、トランザクションの境界はコードの装飾と見なすことができます。

BusinessTask現在のすべてのデータベース操作によって実装されているインターフェースがあるとしましょう。

public interface BusinessTask {
   public void doWork();
}

たとえば、とがありAddSavingsAccountTaskますTransferMoneyTask

これで、最初は、各タスクが個別にコミット(またはロールバック)するようにすべてのタスクを実装できます。しかし、アカウントを作成して一度に送金するタスクを作成したい場合は、トランザクションの境界を変更する必要があるため、問題が発生します。

そのため、アプローチは、トランザクションの境界を設定できるTransactionDecoratorを定義することです。

public class TransactionDecorator implements BusinessTask{

    private final BusinessTask task;

    public TransactionDecorator(BusinessTask task){
        this.task = task;
    }

    @Override
    public void doWork() {
        //beging transaction
        task.doWork();
        //commit or rollback
    }
}

次に、既存のタスクをトランザクションの境界で簡単に装飾できます。

final AddSavingsAccount addSavingsAccountTask = new AddSavingsAccount();
final TransferFunds transferFundsTask = new TransferFunds();

BusinessTask transaction = new TransactionDecorator(new BusinessTask(){

    @Override
    public void doWork() {
        addSavingsAccountTask.doWork();
        transferFundsTask.doWork();
    }
});

transaction.doWork(); //all the magic happens here

今、私はここでパターンを提案しています。コードでのこれの実装は、コードの構造に応じて、設計によって異なります。

その他の参考資料

于 2012-04-05T09:58:19.467 に答える
1

リクエストごとのトランザクションの使用を検討してください。リクエストを処理する前にデータベーストランザクションを開き、後でコミットするフィルタを作成できます。これでうまくいくでしょう。

于 2012-04-05T08:19:31.473 に答える
1

まず、リクエストごとに接続を開かずに、接続プール(おそらくDataSource)からの接続を再利用し、共有スペースに配置します。この場合、静的なThreadLocalフィールドを利用するのが最も簡単です。

フィルタ内:

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
  Connection conn = obtainConnection(); // obtain connection and store it ThreadLocal
  conn.setAutoCommit(false);
  try {
    chain.doFilter(request, response);
  } finally {
    conn.commit();
  }
}

ロガークラスの場合:

public static void logService(String param1, String param2) {
  Connection conn = getConnection(); // obtain thread-local connection
  // your database statements go here
}

一般的に、静力学の使用は避けてください。また、ロギングへのアプローチを再検討することを検討してください。

于 2012-04-05T13:09:44.863 に答える