1

我已经实现了数据库日志记录,以将我的 java weblogic 门户应用程序中的某些详细信息记录到 Oracle DB。为此,我使用连接池来获取连接并使用它来使 jdbc 调用存储过程。

我有一个静态 java 方法 logService,它获取连接对象并调用 SP。这个 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 块中提交后,我最终关闭了连接。我做得对吗?它会起作用吗?

4

3 回答 3

1

事务分界,因为它是安全和日志记录的情况,可以看作是你的代码的装饰。

假设您有一个 interface BusinessTask,它是您当前所有数据库操作正在实现的一个:

public interface BusinessTask {
   public void doWork();
}

例如,您有 aAddSavingsAccountTask和 a 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 回答