我的Java(JDK6)项目使用Spring和JDBCTemplate进行所有数据库访问。我们最近从Spring 2.5升级到Spring 3(RC1)。该项目不使用Hibernate或EJB之类的ORM。
如果我需要读取一堆记录并对其进行一些内部处理,似乎有几种(重载)方法:query,queryForList和queryForRowSet
使用一个而不是另一个的标准应该是什么?有性能差异吗?最佳做法?
您可以推荐一些外部引用资料以进一步研究该主题吗?
最佳答案
我发现访问列表的标准方法是通过query()
方法而不是其他任何方法。 query
和其他方法之间的主要区别在于,您必须实现一个回调接口(interface)(RowMapper
,RowCallbackHandler
或ResultSetExtractor
)来处理结果集。
大部分时间您都会发现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 documentation和JavaDoc for the classes I've mentioned。您还可以查看有关Spring Framework的一些书籍。尽管有些陈旧,但Java Development with the Spring Framework在使用JDBC框架方面有很好的章节。最重要的是,我想说的就是尝试使用每种方法编写一些代码,然后看看最适合您的方法。