【问题标题】:How to process multi-row result in a custom way?如何以自定义方式处理多行结果?
【发布时间】:2020-01-15 13:23:04
【问题描述】:

现在我的方法体如下所示:

jdbcTemplate.query(queryJoiningTwoTables, (rs, rowNum) -> {
    final long id= rs.getLong("id");
    MyObject obj = jobStatusBunchMap.get(id);
    if (obj== null) {
        OffsetDateTime offsetDateTime = rs.getObject("creation_timestamp", OffsetDateTime.class);
        ...
        obj = new MyObject (offsetDateTime ...);
        map.put(id, obj );
    }
    String jobId = rs.getString("job_id");
    obj.getJobIds().add(jobId);
    return null;
});
return map.values();

看起来我以不正确的方式使用 API。

有没有更好的方法来达到同样的效果?

附言

我尝试使用jdbcTemplate#queryForRowSet,但在这种情况下rs.getObject("creation_timestamp", OffsetDateTime.class) 会抛出不支持操作的异常。

【问题讨论】:

  • 1.这不是查询时间 - 业务实体创建时间。 2 我在实体之间有 1-M 关系,我想使用单个 sql 查询在内存中创建对象。

标签: java jdbc java-8 spring-jdbc


【解决方案1】:

有许多选项可以使用 jdbcTemplate 映射结果,包括您的。 也许这会帮助你更好地理解它:

public List<Action> findAllActions() {
    final String selectStatement = "SELECT id,name FROM Actions"; // or your query
    try {

        return jdbcTemplate.query(selectStatement,(resultSet, rowNum) -> {

            int actionId = resultSet.getInt("id");
            String actionName = resultSet.getString("name");

            Action action = new Action();
            action.setId(actionId);
            action.setName(actionName);

            return action;
        });

    } catch (EmptyResultDataAccessException e) {
        LOGGER.error("Get all actions - empty set", e);
        return Collections.emptyList();
    }
}

如果没有 lambda 表达式,您可以像这样使用 jdbcTemplate 查询:

public List<Action> findAllActions() {
    final String selectStatement = "SELECT id,name FROM Actions"; // or your query
    try {

        return jdbcTemplate.query(selectStatement, getActionRowMapper());

    } catch (EmptyResultDataAccessException e) {
        LOGGER.error("Get all actions - empty set", e);
        return Collections.emptyList();
    }
}
private RowMapper<Action> getActionRowMapper() {
    return (resultSet, rowNum) -> {

        int actionId = resultSet.getInt("id");
        String actionName = resultSet.getString("name");

        return action;
    };
}

如您所见,jdbcTemplate.query 方法的第二个参数采用RowMapper&lt;Action&gt; 类型,但使用 lambdas 表达式隐藏。除了为每一行映射结果集并返回结果之外,此选项“限制”您进行任何其他操作。最终结果最终将是List 的操作。

第二个选项是使用ResultSetExtractor,它可以让您循环遍历结果集并为您提供更大的灵活性。查询是一样的,只是 jdbcTemplate.query 方法的第二个参数会改变。为此,我会亲自实现 ResultSetExtractor 并覆盖 extractData 方法,或者如果您不需要其他任何东西来映射结果,您也可以执行与上述相同的操作

public List<Group> findGroups() {
    final String selectStatement = "SELECT stud.id, stud.name, gr.id, gr.name FROM student stud INNER JOIN group gr ON gr.id=stud.group_id ORDER BY stud.id"; // or your query
    try {

        return jdbcTemplate.query(selectStatement, new GroupExtractor() );

    } catch (EmptyResultDataAccessException e) {
        LOGGER.error("Get all groups - empty set", e);
        return Collections.emptyList();
    }
}


public class GroupExtractor implements ResultSetExtractor<List<Group>> {
@Override
public List<Group> extractData(ResultSet resultSet) {
    Map<Group, List<Student>> studentsGroup= new HashMap<>();
    List<Group> groups = new ArrayList<>();
    try {
        while (resultSet.next()) {
          int studentId = resultSet.getInt("stud.id");
            String studentName = resultSet.getString("stud.name");
            int groupId = resultSet.getInt("gr.id");
            String groupName = resultSet.getString("gr.name");

            Group group = createGroup(groupId, groupName);
            Student student = createStudent(studentId, studentName);

            studentsGroup.putIfAbsent(group, new ArrayList<>());
            studentsGroup.get(group).add(student);

        }

        studentsGroup.forEach((group,students) ->{
            group.setStudents(students);
            groups.add(group);
        }

        return groups;

    } catch (SQLException e) {
        LOGGER.info("An error occured during extracting data", e);
    }
    return actions;
 }

private Student createStudent(String studentId, String studentName)
{
  Student student=new Student();
  student.setId(studentId);
  student.setName(studentName);
  return student;
}

//idem for createGroup
}

【讨论】:

  • 看来你误解了我的问题。我的选择返回 100(例如)行但我想获得少于 100 个(比如说 20 个)对象的问题,因为它是使用连接查询
  • 那么最好在 SQL 查询中使用 mysql 中的 "LIMIT" 子句。 (每次有机会时使用 MySQL 子句而不是 java 代码。让 MySQL 做“艰苦的工作”)
  • 你根本不懂我。假设我在一个表 GROUP 中有 5 行,每个组在 STUDENT 表中有 20 个对应的行。如果执行连接 2 个表的查询,我们会得到 100 行。但我想得到 5 组对象的结果,每个组都有填充的学生集合
  • 请查看我回答中的最后一个代码 sn-p(我已对其进行了修改)并告诉我这是否是您需要知道的(在这种情况下,请不要忘记覆盖 Group 和 Student 类中的 equals() 和 hashCode() 方法)
  • 是的,这就是我要找的
猜你喜欢
  • 2015-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-26
  • 2021-12-24
  • 2015-05-31
  • 1970-01-01
  • 2018-08-01
相关资源
最近更新 更多