亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

當我需要在關閉 ResultSet 之前從 ResultSet 填充時,如何抽象出 JDBC 代碼?

當我需要在關閉 ResultSet 之前從 ResultSet 填充時,如何抽象出 JDBC 代碼?

開滿天機 2022-04-28 16:48:28
我正在開發一個 Java 應用程序,該應用程序對數據庫進行大量 JDBC 查詢,每個查詢都在一個單獨的方法中指定,格式大致如下。public static void sampleJDBCQuery(String query, DBUtil dbUtil, DataStructure dataStructure) {    ResultSet rs = null;    Handle handle = null;    Connection conn = null;    Statement stmt = null;    LOGGER.debug("Executing query = {}", query);    try {        handle = dbUtil.getConnectionHandle();        conn = handle.getConnection();        if (conn != null) {            stmt = conn.createStatement();            if (stmt != null) {                rs = stmt.executeQuery(query);                if (rs != null) {                    while (rs.next()) {                        // populate dataStructure using rs                    }                }            }        }    } catch (Exception e) {        Metrics.markMeter("vertica.read.error");        LOGGER.error(e.getMessage(), e);    } finally {        DBUtil.closeResultSet(rs);        DBUtil.closeStatement(stmt);        DBUtil.close(handle);        LOGGER.debug("Finished query = {}", query);    }}使用上述格式的許多不同示例查詢(和數據結構類),我的代碼庫一直在大幅增長。我的目標是擁有一個幫助方法,為我抽象出大部分 JDBC 邏輯。我的第一個想法是有一個具有以下簽名的方法。public static ResultSet executeJDBCQuery(String query, DBUtil dbUtil)然后我可以遍歷 的行并為每一行ResultSet填充相關內容。DataStructure問題是我仍然必須關閉返回ResultSet并ResultSet以不同的方法關閉似乎是糟糕的設計。我想我正在尋找可能類似于 Python 的函數裝飾器概念的東西,這樣我就可以“裝飾”一個 JDBC 查詢來處理sampleJDBCQuery上面出現的大部分樣板。我怎么能做到這一點?
查看完整描述

1 回答

?
當年話下

TA貢獻1890條經驗 獲得超9個贊

您可以傳入一個策略來告訴該方法如何將行映射到對象上的字段。


這就是 spring-jdbc 所做的,它將RowMapper定義為:


public interface RowMapper<T> {

    T mapRow(ResultSet resultSet, int rowNum) throws SQLException;

}

這就是您可以更改方法的方式,包括合并 rowMapper:


public static <T> List<T> queryList(String query, Connection conn, RowMapper<T> rowMapper) throws SQLException {

    LOGGER.debug("Executing query = {}", query);

    try {

        Statement stmt = conn.createStatement();

        ResultSet rs = stmt.executeQuery(query);

        List<> list = new ArrayList<>();    

        while (rs.next()) {

            list.add(rowMapper.mapRow(rs, list.size() + 1)); 

        }

        return list;

    } finally {

        DBUtil.closeResultSet(rs);

        DBUtil.closeStatement(stmt);

        LOGGER.debug("Finished query = {}", query);

    }

}

在這里捕獲所有異常并不好,因為如果出現問題,您希望能夠使用異常來退出當前操作。否則,您將在日志中有多個錯誤堆棧跟蹤,其中一個是發生錯誤的地方,另一個是下游,當您的代碼期望出現不是由于前一個錯誤導致的結果時,您的代碼會失敗。當第一個錯誤發生時快速失敗。


下一步將參數化您的查詢,因此您不必將參數值括在引號中或擔心 sql 注入。有關spring-jdbc 如何處理此問題的示例,請參見此答案。


我把連接的東西移出了方法;傳入連接允許您在同一個 JDBC 本地事務中執行多個 sql 語句。(連接仍然需要關閉,這只是錯誤的地方。)


同樣在這里傳遞這個句柄是違反德墨忒耳法則的:


特別是,一個對象應該避免調用另一個方法返回的成員對象的方法。對于許多使用點作為字段標識符的現代面向對象語言,該法則可以簡單地表述為“僅使用一個點”。也就是說,代碼 abMethod() 違反了 a.Method() 沒有的規律。打個比方,想讓狗走路,不是直接命令狗腿走路,而是直接讓狗走路。取而代之的是命令狗,然后狗命令自己的腿。


即使您只做只讀的事情,讓查詢共享事務也可以提高一致性并提高性能。使用 Spring 使用事務不那么痛苦,您可以使用注釋以聲明方式實現事務,以顯示您希望邊界在哪里。


這里的全局答案是:最好采用一個預先存在的工具(spring-jdbc 或類似的東西),它們已經解決了你甚至還沒有考慮過的問題,而不是零碎地重新發明它,這就是你顯然要走的路。


查看完整回答
反對 回復 2022-04-28
  • 1 回答
  • 0 關注
  • 172 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號