Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当我需要在关闭ResultSet之前从ResultSet中填充时,如何提取JDBC代码?_Java_Jdbc - Fatal编程技术网

Java 当我需要在关闭ResultSet之前从ResultSet中填充时,如何提取JDBC代码?

Java 当我需要在关闭ResultSet之前从ResultSet中填充时,如何提取JDBC代码?,java,jdbc,Java,Jdbc,我正在开发一个Java应用程序,它对一个数据库执行许多JDBC查询,每个查询都是用一个单独的方法指定的,格式大致如下 public static void sampleJDBCQuery(String query, DBUtil dbUtil, DataStructure dataStructure) { ResultSet rs = null; Handle handle = null; Connection conn = null; Statement stm

我正在开发一个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
的行上循环,并为每一行填充相关的
数据结构。问题是,我仍然必须关闭返回的
ResultSet
,而用另一种方法关闭
ResultSet
似乎是一种糟糕的设计


我想我想要的可能是类似于Python的函数装饰器概念的东西,这样我就可以“装饰”JDBC查询,以处理上面
sampleJDBCQuery
中的大部分样板文件。如何实现这一点?

您可以传入一个策略,告诉方法如何将行映射到对象上的字段

spring jdbc就是这样做的,它定义了:

公共接口行映射器{
T mapRow(ResultSet ResultSet,int rowNum)抛出SQLException;
}
以下是更改方法的方法,包括合并行映射器:

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);
    }
}
publicstaticlist queryList(字符串查询、连接连接、行映射器行映射器)抛出SQLException{
debug(“正在执行查询={}”,查询);
试一试{
语句stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(查询);
列表=新的ArrayList();
while(rs.next()){
add(rowMapper.mapRow(rs,list.size()+1));
}
退货清单;
}最后{
DBUtil.closeResultSet(rs);
DBUtil.closeStatement(stmt);
debug(“完成的查询={}”,查询);
}
}
在这里捕获所有异常并不好,因为如果出现问题,您希望能够使用异常退出当前操作。否则,您将在日志中有多个错误堆栈跟踪,一个在此处发生错误,另一个在下游发生错误,当您的代码期望出现一个不是由于前一个错误导致的结果时,代码将失败。当第一个错误发生时,快速失败

下一步是参数化查询,这样就不必将参数值括在引号中或担心sql注入。有关SpringJDBC如何处理此问题的示例,请参见

我将连接内容从方法中移出;传入连接允许在同一个JDBC本地事务中执行多个sql语句。(连接仍然需要关闭,这是一个错误的地方。)

在此传递此句柄也违反了:

特别是,对象应该避免调用另一个方法返回的成员对象的方法。对于许多使用一个点作为字段标识符的现代面向对象语言来说,这个法则可以简单地表述为“只使用一个点”。也就是说,代码a.b.Method()违反了法律,而a.Method()则没有。作为一个类比,当一个人想要一只狗走路时,他不会命令狗的腿直接走路;取而代之的是,一个人命令狗,然后狗命令它自己的腿

即使您只做只读的工作,让查询共享事务也可以提高一致性并提高性能。使用事务对Spring来说不那么痛苦,您可以使用注释以声明方式实现事务,以显示边界的位置


这里的大局答案是:最好采用一个预先存在的工具(SpringJDBC或类似工具),它们已经解决了您甚至还没有考虑的问题,而不是零碎地重新设计它,这显然是您要走的路

也许您需要的是某种委托模式,在这种模式中,您使用一个方法定义一个通用接口,该方法将ResultSet作为参数,并从中提取当前值(我这样做的目的是委托只提取“当前”值)行,通过行进行集成的责任仍然是调用方法的责任)所有这些空检查都应该是完全不必要的;这些方法永远不应该返回
null
(可能除了
handle.getConnection
,但是如果它可以返回
null
,那么你就应该解决这个问题)。如果没有强制使用JDBC的要求,在重新发明轮子之前,使用类似Hibernate的ORM。Hibernate在某些方面很好。但它有一个学习曲线,可以使事情变得更加模糊。当然可以,看看,但不是每个人都可以。
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);
    }
}