【问题标题】:Using a query inside RowMapper在 RowMapper 中使用查询
【发布时间】:2014-08-20 12:45:12
【问题描述】:

在 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 实现相同的功能,

提前致谢

【问题讨论】:

  • 您正在做的事情对于常规 JDBC 代码来说不是一个好主意!性能受到重复查询数据库的影响。您最好使用连接查询,然后提取相关数据。不用说,像您建议的那样使用 RowMapper 将您的 JDBC 代码传输到 Spring 会更糟。 RowMapper 应该是一个创建 DTO 的哑对象。仅此而已
  • 是的,我知道,但仅此要求就有上述机会。而且我确信第一个查询将只包含 3 到 4 个结果。这样就不会导致性能问题。有没有办法使用spring jdbc来做到这一点?
  • 即使考虑到我正在将我的结果集添加到集合中并再次对其进行迭代
  • 我强烈建议将两个查询合并为一个查询select * from table where column in (select distinct(column) from table),然后您可以使用RowMapper 映射实际结果。您现在正在执行 5 个查询而不是 5 个查询并简化了您的代码。
  • 一个观察:您的查询让 SQL 注入攻击。在查询+rs.getString(1) 中附加一些东西是一种不好的做法,请改用setParameter 方法。 JdbcTemplate 支持这样做。

标签: java sql spring resultset jdbctemplate


【解决方案1】:

正如多人所说,您的解决方案虽然可能有效,但效率不高,您基本上落入了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 如果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 并获得所有MODEL 对象的List,然后进行分区。您可以使用 Google Guava 来简化此操作,或者如果您使用的是 Java 8,则可以使用新的流 API。

【讨论】:

  • 感谢您的回答,将尝试更新您
【解决方案2】:

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

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

在任何情况下,您都不希望对从第一个查询返回的每个项目进行单独的查询,因为这会很慢,即使对于少量项目也是如此。但是,如果您觉得必须,则将第一个查询的结果存储在一个列表中,然后针对列表中的每个项目发出另一个查询。

TLDR;不,JDBCTemplate 没有提供一种机制来做你想做的事,主要是因为它通常被认为是编程反模式的规范示例。

【讨论】:

  • 实际上JdbcTemplate 确实通过使用ResultSetExtractor 提供了这样的机制。您可以使用它来迭代自己并再次执行查询,不是我会建议它,而是唉。
  • @M.Deinum 我需要的最终结果类似于Map&lt;Result of 1st query, list of 2nd query values &gt; 而我需要的原因可能与第一个查询结果重复。但我需要单个值
  • 从您发布的代码来看,您不能有重复项,因为您使用了 distinct。
  • 好的。但是是否有可能获取查询的第二部分的值?select distinct(column) from table 可能有很多条目,我使用 distinct 的原因是我获得了键的唯一值。在第二个查询中,我使用它来获取与 distinct(column) 关联的所有值
  • @M.Deinum 我已经编辑了我的帖子,请立即查看。这正是我希望用jdbc template 做的事情。有可能吗?
猜你喜欢
  • 2023-03-16
  • 2022-01-18
  • 1970-01-01
  • 2012-01-14
  • 2016-09-07
  • 1970-01-01
  • 2020-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多