我的Java(JDK6)项目使用SpringJDBCTemplate进行所有数据库访问。我们最近从Spring 2.5升级到Spring 3(RC1)。该项目不使用HibernateEJB之类的ORM。

如果我需要读取一堆记录并对其进行一些内部处理,似乎有几种(重载)方法:query,queryForList和queryForRowSet

使用一个而不是另一个的标准应该是什么?有性能差异吗?最佳做法?

您可以推荐一些外部引用资料以进一步研究该主题吗?

最佳答案

我发现访问列表的标准方法是通过query()方法而不是其他任何方法。 query和其他方法之间的主要区别在于,您必须实现一个回调接口(interface)(RowMapperRowCallbackHandlerResultSetExtractor)来处理结果集。

大部分时间您都会发现RowMapper。当结果集的每一行对应于列表中的一个对象时,将使用它。您只需要实现一个方法mapRow即可在其中填充行中返回的对象的类型。 Spring也有一个BeanPropertyRowMapper,它可以通过将bean属性名称与列名称进行匹配来填充列表中的对象(注意,此类是为了方便而不是性能)。

当您需要结果不仅仅是一个简单的列表时,RowCallbackHandler更为有用。使用这种方法时,您必须自己管理返回对象。当我需要将 map 结构作为返回类型时(例如,用于树表的分组数据或基于主键创建自定义缓存时),我通常会使用此方法。

当您要控制结果的迭代时,将使用ResultSetExtractor。您将实现一个单独的方法extractData,它将作为对query的调用的返回值。只有在必须构建一些自定义数据结构时,我才发现自己在使用该数据结构,而使用其他回调接口(interface)中的任何一个来构建这些数据结构都更加复杂。
queryForList()方法很有值(value),因为您不必实现这些回调方法。有两种使用queryForList的方法。第一种是,如果您仅查询数据库中的单个列(例如,字符串列表),则可以使用以Class作为参数的方法版本来自动为您提供这些类的仅对象列表。

调用queryForList()的其他实现时,您将获得一个列表,其中每个条目都是每个列的映射。尽管这样做很不错,但是您节省了编写回调方法的开销,但是处理此数据结构非常麻烦。由于 map 的值类型为Object,因此您会发现自己进行了大量的转换。

实际上,我从未见过在野外使用queryForRowSet方法。这会将整个查询结果加载到由Spring SqlRowSet包装的CachedRowSet对象中。在使用此对象时,我看到一个很大的缺点,即如果将SqlRowSet传递到应用程序的其他层,则会将这些层耦合到数据访问实现。

除了我在BeanPropertyRowMapper中提到的那样,您应该不会在这些调用之间看到任何巨大的性能差异。如果您正在处理大型结果集的某些复杂操作,则可以通过针对特定情况编写优化的ResultSetExtractor来获得一些性能提升。

如果您想了解更多信息,请查阅Spring JDBC documentationJavaDoc for the classes I've mentioned。您还可以查看有关Spring Framework的一些书籍。尽管有些陈旧,但Java Development with the Spring Framework在使用JDBC框架方面有很好的章节。最重要的是,我想说的就是尝试使用每种方法编写一些代码,然后看看最适合您的方法。

10-07 19:07
查看更多