2

我已经有一段时间没有进行任何 Java 编程了。我发现自己有点卡住了。

我的问题是我在 tomcat 中有一个池化数据库连接。那工作得很好。但是需要很多样板。

    public void init() {
    Connection conn = null;
    ResultSet rst = null;
    Statement stmt = null;
    try {

        //SETUP 
        Context initContext = new InitialContext();
        Context envContext = (Context) initContext.lookup("java:/comp/env/jdbc");
        OracleDataSource ds = (OracleDataSource) envContext.lookup("tclsms");

        if (envContext == null) throw new Exception("Error: No Context");
        if (ds == null) throw new Exception("Error: No DataSource");
        if (ds != null) conn = ds.getConnection();
        if (conn == null) throw new Exception("Error: No Connection")

        message = "Got Connection " + conn.toString() + ", ";

        //BODY 
        stmt = conn.createStatement();
        rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

        if (rst.next()) message = rst.getString(1);



        //TEAR DOWN 
        rst.close();
        rst = null;
        stmt.close();
        stmt = null;
        conn.close(); // Return to connection pool
        conn = null; // Make sure we don't close it twice
    } catch (Exception e) {
        e.printStackTrace();
        //TODO proper error handling 
    } finally {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        if (rst != null) {
            try {
                rst.close();
            } catch (SQLException e) {;}
            rst = null;
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {;}
            stmt = null;
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {;}
            conn = null;
        }
    } //END FINALLY
} //END INIT

所以我想做相当于将一个方法传递给 init ,它将在函数体中运行。我知道我不能在 Java 中做到这一点。但我确信必须有一个很好的方法来做到这一点。或者至少是这类事情的最佳实践。

非常感谢任何帮助。

4

4 回答 4

1
abstract class UseDBConnectionTask extends Runnable {

    private Connection conn;

    public UseDBConnectionTask(){
        setUp();
    }

    // should probably refine this to specific exceptions
    public abstract void process() throws Exception; 

    public void run(){

        try{
            process()
            // this should catch specific exceptions
        } catch (Exception e){
            // handle
        } finally {
            tearDown();
        }
    }

    Connection getConnection(){
        return conn;
    }

    public void setUp(){
        // SETUP here
        // set the conn field
    }

    public void tearDown(){
        // TEAR DOWN here
    }
}

像这样使用:

UseDBConnectionTask dbTransaction = new UseDBConnectionTask(){

    public void process(){
        // do processing 
        // use conn via getConnection()
        // eg
        Statement stmt = conn.createStatement();
        ResultSet rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

        String message = null;
        if (rst.next()) message = rst.getString(1);
    }

}

new Thread(dbTransaction).start();

扩展 Runnable 的优点是您可以将此实例传递给线程池或类似的。只需要小心线程问题。它还假设拆解总是相同的。

于 2013-05-15T23:14:09.103 回答
1

您应该更喜欢委托而不是继承。以上可以/将起作用,但没有经过深思熟虑。

在主类上实现 Runnable 会使它被滥用,因为 'run()' 方法是公共的。

第二个改进是用于将您的活动委托给接口(并且可以像函数指针一样传递该接口,而扩展类则不能)。此外,它使它对 Spring 友好

这允许动作实现者决定他们是否需要多线程行为。您可以注入复合材料、缓存委托等,而主类是不明智的。这符合关注点分离的良好设计实践

public class MyClass {

    private Action action;

    public MyClass (Action action) {
        this.action = action;
    }

    public void connection() {

        try{
            action.perform()
        } catch (Exception e){
            // handle
        } finally {
            tearDown();
        }
    }

    Connection getConnection(){
        return conn;
    }

    private void setUp(){
        // SETUP here
        // set the conn field
    }

    private void tearDown(){
        // TEAR DOWN here
    }

}
于 2013-05-15T23:46:04.230 回答
0
private void Todo(Context initContext, Context envContext, OracleDataSource ds){

            if (envContext == null) throw new Exception("Error: No Context");
            if (ds == null) throw new Exception("Error: No DataSource");
            if (ds != null) conn = ds.getConnection();
            if (conn == null) throw new Exception("Error: No Connection")

            message = "Got Connection " + conn.toString() + ", ";

            //BODY 
            stmt = conn.createStatement();
            rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

            if (rst.next()) message = rst.getString(1);



            //TEAR DOWN 
            rst.close();
            rst = null;
            stmt.close();
            stmt = null;
            conn.close(); // Return to connection pool
            conn = null; // Make sure we don't close it twice
        } catch (Exception e) {
            e.printStackTrace();
            //TODO proper error handling 
        } finally {
            // Always make sure result sets and statements are closed,
            // and the connection is returned to the pool
            if (rst != null) {
                try {
                    rst.close();
                } catch (SQLException e) {;}
                rst = null;
            }

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {;}
                stmt = null;
            }

            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {;}
                conn = null;
            }
        } //END FINALLY
}

然后像这样从你的 Init 调用它this. Todo(initContext,envContext , ds

于 2013-05-15T23:07:46.687 回答
0
interface IDbAction {
    public DbActionResult runAction(Connection conn);
}

class DbActionResult {

    Statement statement;
    ResultSet resultSet;

    public DbActionResult(Statement statement, ResultSet resultSet){
        this.statement = statement;
        this.resultSet = resultSet;
    }

    public void getStatement(){ return this.statement; }
    public void getResultSet(){ return this.resultSet; }
}

public void runAgainstDB(IDbAction action) {

    Connection conn = null;
    ResultSet rst = null;
    Statement stmt = null;

    try {

        //SETUP 
        Context initContext = new InitialContext();
        Context envContext = (Context) initContext.lookup("java:/comp/env/jdbc");
        OracleDataSource ds = (OracleDataSource) envContext.lookup("tclsms");

        if (envContext == null) throw new Exception("Error: No Context");
        if (ds == null) throw new Exception("Error: No DataSource");
        if (ds != null) conn = ds.getConnection();
        if (conn == null) throw new Exception("Error: No Connection")

        message = "Got Connection " + conn.toString() + ", ";

        //BODY 
        DbActionResult actionResult = action.runAction(conn);

        //TEAR DOWN 

        if((rst = actionResult.getResultSet()) != null){
            rst.close();
            rst = null;
        }

        if((stmt = actionResult.getStatement()) != null){
            stmt.close();
            stmt = null;
        }

        actionResult = null;

        conn.close(); // Return to connection pool
        conn = null; // Make sure we don't close it twice
    } catch (Exception e) {
        e.printStackTrace();
        //TODO proper error handling 
    } finally {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        if (rst != null) {
            try {
                rst.close();
            } catch (SQLException e) {;}
            rst = null;
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {;}
            stmt = null;
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {;}
            conn = null;
        }
    } //END FINALLY
} //END 

像这样使用:

IDbAction action = new IDbAction(){

    public DbActionResult prcoessAction(Connection conn){
        Statement stmt = conn.createStatement();
        ResultSet rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");

        if (rst.next()) message = rst.getString(1);

        return new DbActionResult(stmt, rst);
    }

}

runAgainstDB(action);
于 2013-05-15T23:32:02.633 回答