【问题标题】:How to use Spring jdbc templates (jdbcTemplate or namedParameterJDBCTem) to retrieve values from database如何使用 Spring jdbc 模板(jdbcTemplate 或 namedParameterJDBCTem)从数据库中检索值
【发布时间】:2012-12-20 13:31:46
【问题描述】:

离春天还有几天。将 Spring-JDBC 集成到我的 Web 应用程序中。我成功地在我的数据库上执行了 CRUD 操作,对样板代码减少印象深刻。但是我没有使用NamedParameterJDBCTemplate 中提供的query*() 方法。互联网上的大多数示例都提供了RowMapperResultSetExtractor 的用法。虽然这两种用途都很好,但它迫使我创建必须实现这些接口的类。我必须为我为数据库加载的每种类型的数据创建 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 的一个实例。请为我提供这些情况的解决方案。

【问题讨论】:

    标签: java spring spring-jdbc


    【解决方案1】:

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

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

    queryForMap

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

    【讨论】:

    • 感谢您的回复。出色的。您的回答鼓励我进一步探索 API。现在我对 NamedParameterJDBCTemplate 中各种方法的工作有了一些了解。 :)
    【解决方案2】:

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

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

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

    【讨论】:

    • 我要从javadocs 中添加一个警告:请注意,该类旨在提供便利而不是高性能。为获得最佳性能,请考虑使用自定义 RowMapper。
    • “我们应该忘记小的效率,比如说大约 97% 的时间:过早的优化是万恶之源”- Donald Knuth
    • @hyness 不错。它适用于我项目中的大多数情况。但是,有些地方 bean 名称和列名称不匹配。我想它可能会失败。我弄错了吗?
    • 无论 bean 属性是否匹配,您都可以使用此映射器。当 bean 属性和列名不匹配时,使用 as 语句使其匹配。 Spring会将下划线转换为驼峰式。上面的例子展示了如何使用它。
    【解决方案3】:

    通常,是的:对于大多数查询,您将创建一个 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;
        }
      }
    

    【讨论】:

      【解决方案4】:

      在您的第一个示例中,我将创建一个 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;
          }
      

      【讨论】:

      • 感谢您的回复。对于第二个示例,我期望 MangaBeanMapper 为所有不存在的列采用 null。但是当它无法找到它们时会引发异常。如何向它们添加 null 。你能建议我一个实现你想法的例子/网址吗?
      • @RickeshJohn 很简单,只是不要调用设置器,或者为它们提供默认值 - 最好的解决方案将取决于 managabean。查看更新
      猜你喜欢
      • 1970-01-01
      • 2011-11-04
      • 2012-03-22
      • 1970-01-01
      • 2015-01-20
      • 1970-01-01
      • 2019-06-15
      • 1970-01-01
      • 2016-09-08
      相关资源
      最近更新 更多