3

离春天还有几天。将 Spring-JDBC 集成到我的 Web 应用程序中。我成功地在我的数据库上执行了 CRUD 操作,对样板代码减少印象深刻。但我没有query*()使用NamedParameterJDBCTemplate. 互联网上的大多数示例都提供了RowMapperor 或ResultSetExtractor. 虽然这两种用途都很好,但它迫使我创建必须实现这些接口的类。我必须为我为数据库加载的每种类型的数据创建 bean(或者我可能弄错了)。

问题出现在我使用过这样的代码部分:

String query="select username, password from usertable where username=?"
ps=conn.prepareStatement(query);
ps.setString(username);
rs=ps.executeQuery();

if(rs.next()){
    String username=rs.getString("username");
    String password=rs.getString("password")

    //Performs operation on them
}  

由于这些值没有存储在任何 bean 中并直接使用,因此我无法在这种情况下集成 jdbcTemplate。当我从数据库中仅提取 bean 中存在的部分属性时,会出现另一种情况。例子:

public class MangaBean{
    private String author;
    private String title;
    private String isbn;
    private String releaseDate;
    private String rating;

    //getters and setters

} 

映射器:

public class MangaBeanMapper implements RowMapper<MangaBean>{

    @Override
    public MangaBean mapRow(ResultSet rs, int arg1) throws SQLException {
        MangaBean mb=new MangaBean();
        mb.setAuthor(rs.getString("author"));
        mb.setTitle(rs.getString("title"));
        mb.setIsbn(rs.getString("isbn"));
        mb.setReleaseDate(rs.getString("releaseDate"));
        mb.setRating(rs.getString("rating"));
        return mb;
    }
}

上述安排运行良好,如下所示:

String query="select * from manga_data where isbn=:isbn"
Map<String, String> paramMap=new HashMap<String, String>();
paramMap.put("isbn", someBean.getIsbn());
return template.query(query, paramMap, new MangaBeanMapper());

但是,如果我只想从我的数据库中检索两个/三个值,我不能使用上面的模式,因为它会生成一个BadSqlGrammarException: releaseDate does not exist in ResultSet. 例子 :

String query="select title, author where isbn=:isbn"
Map<String, String> paramMap=new HashMap<String, String>();
paramMap.put("isbn", someBean.getIsbn());
return template.query(query, paramMap, new MangaBeanMapper());

模板是NamedParameterJDBCTemplate. 请为我提供这些情况的解决方案。

4

4 回答 4

3

其他答案是明智的:您应该创建一个 DTO bean,或者使用BeanPropertyRowMapper.

但是如果你希望能够拥有比 BeanPropertyRowMapper 更多的控制权,(或者反射让它太慢),你可以使用

queryForMap

方法,它将返回一个 Maps 列表(每行一个),返回的列作为键。因为您可以get(/* key that is not there */)在不引发异常的情况下调用 Map(它只会返回 null),所以您可以使用相同的代码来填充您的对象,而不管您选择了哪些列。

于 2012-12-20T15:31:26.923 回答
2

你甚至不需要编写自己的 RowMapper,只需使用spring 提供的BeanPropertyRowMapper即可。它的工作方式是匹配返回到 bean 属性的列名。您的查询具有与您的 bean 完全匹配的列,如果不是,您将在 select 中使用 as ,如下所示...

-- This query matches a property named matchingName in the bean
select my_column_that doesnt_match as matching_name from mytable;

BeanPropertyRowMapper应该适用于您列出的两个查询。

于 2012-12-20T15:09:38.180 回答
1

在您的第一个示例中,我将创建一个 DTO Bean/Value 对象来存储它们。它是一种普遍实现的模式是有原因的,它需要几分钟的时间来编写代码并提供许多长期的好处。

在您的第二个示例中,在您不设置字段的地方创建 rowmapper 的第二个实现,或在必要时向 mangabean 提供空值/替代值:

    @Override
    public MangaBean mapRow(ResultSet rs, int arg1) throws SQLException {
    MangaBean mb=new MangaBean();
    mb.setAuthor(rs.getString("author"));
    mb.setTitle(rs.getString("title"));
   /* mb.setIsbn("unknown");*/
    mb.setReleaseDate("unknown");
    mb.setRating(null);
    return mb;
    }
于 2012-12-20T13:45:24.137 回答
1

通常,是的:对于大多数查询,您将创建一个 bean 或对象来将结果转换为。我建议在大多数情况下,这是您想要做的。

但是,您可以创建一个将结果集映射到映射而不是 bean 的 RowMapper,就像这样。缺点是会丢失 bean 的类型管理,并且您将依赖 jdbc 驱动程序为每列返回正确的类型。

正如@NimChimpskey 刚刚发布的那样,最好创建一个小 bean 对象:但如果您真的不想这样做,这是另一种选择。

  class SimpleRowMapper implements RowMapper<Map<String, Object>> {
    String[] columns;

    SimpleRowMapper(String[] columns) {
      this.columns = columns;
    }

    @Override
    public Map<String, Object> mapRow(ResultSet resultSet, int i) throws SQLException {
      Map<String, Object> rowAsMap = new HashMap<String, Object>();
      for (String column : columns) {
        rowAsMap.put(column, resultSet.getObject(column));
      }
      return rowAsMap;
    }
  }
于 2012-12-20T13:48:06.800 回答