在RowMapper中使用查询

时间:2014-08-20 12:45:12

标签: java sql spring resultset jdbctemplate

在java中,我会做类似下面的事情来迭代resultset并形成查询,

public Map<String, List<MODEL>> fun(){
Map<String, List<MODEL>> map = new TreeMap<String, List<MODEL>>();      
        LinkedHashSet<String> set = new LinkedHashSet<String>();

            String sql = "select distinct(column) from table where conditions orderby column ";
            ResultSet rslt = stmt.executeQuery(sql);
            while (rslt.next()) {
                al.add(rslt.getString(1));
            }
            for (String s : al) {           
                List<MODEL> list = new ArrayList<MODEL>();
                String sql2 = "select * from table where column="+s;
                ResultSet rslt2 = stmt.executeQuery(sql2);
                while (rslt2.next()) {
                    MODEL obj = new MODEL();
                    // set values to setters from resultset
                    list.add(obj);
                }
                map.put(s, list);
            }
            return map;
            }

我使用单独查询的原因是,我将不同的值添加到地图键及其对应的值(如列表)到地图的值。注意 (在结果中它具有 column1 的重复值),但我需要将它们存储为地图键,从而使其成为唯一的。 我还需要所有相关的值,以便填充列表

如何使用JdbcTemplate

实现相同的功能

提前致谢

2 个答案:

答案 0 :(得分:2)

正如多人所说,你的解决方案效率不高,虽然它可能有效但你基本上陷入了1+N select problem的陷阱。 1个查询检索一个id,然后为每个id检索另一个查询(因此1 + N选择)。

最好只编写一个查询,一次性检索所有内容。查看您的代码,您有以下2个查询,根据它们的外观,它们在同一个表上运行。

String sql1 = "select distinct(column) from table where conditions orderby column ";
String sql2 = "select * from table where column="+s

现在,您可以将第一个查询作为第二个查询的子选择

String sql = "select * from table where column in (select distinct(column) from table where conditions) order by column";

然而,再次从它的外观来看,将第二个查询中的where子句放在一起也是可能的(或者甚至更容易)。

String sql = "select * from table where conditions order by column";

您现在可能会获取您的密钥(在Map中)获取多个值。您可以自己对结果使用ResultSetExtractor循环或使用为您进行迭代的RowCallbackHandler做两件事。

您需要做的只是对结果进行迭代(或让JdbcTemplate为您执行此操作),如果Map已经存在,则{key> List。如果是先添加一行,则首先创建List并将其添加到结果Map

public Map<String, List<MODEL>> fun(){
    final Map<String, List<MODEL>> map = new TreeMap<String, List<MODEL>>();      

    String sql = "select * from table where conditions order by column";
    getJdbcTemplate().query(sql, new RowCallbackHandler() {
        public void processRow(ResultSet resultSet) throws SQLException {
            String key = rs.getString("column");
            List rows = map.get(key);
            if (rows == null) {
                rows = new new ArrayList<MODEL>();
                map.put(key, rows);
            }
             MODEL obj = new MODEL();
            // set values to setters from resultset
            rows.add(obj);
        }, "arguments"); 
    return map;
}

另一种解决方案,只有在“列”也是MODEL类的一部分时才有效。这样,您可以使用RowMapper并获取所有List个对象的MODEL,然后进行分区。您可以使用Google Guava使其更容易实现,或者如果您使用的是Java 8,则可以使用新的流api。

答案 1 :(得分:1)

正如@geoand所说,最好的事情(无论是直接的JDBC代码还是使用JDBCTemplate)都是使用Join进行单个查询。

但是,正如您在评论中提到的那样,您绝对肯定第一个查询的结果集总是小(可疑),那么您可以存储从中检索到的值首先在列表中查询,然后使用列表作为参数,使用“in”子句执行第二次查询。这将导致两个查询。

在任何情况下,你真的不想对第一个查询返回的每个项目进行单独的查询,因为即使对于少量项目,这也会非常慢。但是,如果您认为必须,则将第一个查询的结果存储在列表中,然后为列表中的每个项目发出另一个查询。

TLDR;不,JDBCTemplate不提供执行所需操作的机制,主要是因为它通常被认为是编程反模式的规范示例。