My Java(JDK6)项目使用Spring和JDBCTemplate进行所有数据库访问。我们最近从Spring 2.5升级到Spring 3(RC1)。该项目不使用Hibernate或EJB等ORM。
如果我需要读取一堆记录,并用它们做一些内部处理,似乎有几个(重载)方法:query,queryForList和queryForRowSet
使用一个而不是另一个的标准应该是什么?有任何性能差异吗?最佳做法?
您是否可以推荐一些外部参考资料以进一步研究该主题?
答案 0 :(得分:40)
我发现作为列表访问的标准方法是通过query()
方法而不是任何其他方法。 query
与其他方法之间的主要区别在于您必须实现其中一个回调接口(RowMapper
,RowCallbackHandler
或ResultSetExtractor
)来处理结果集。
RowMapper
可能是大多数时候你会发现的。当结果集的每一行对应列表中的一个对象时使用它。您只需要实现一个方法mapRow
,您可以在其中填充行中的对象类型并将其返回。 Spring还有一个BeanPropertyRowMapper
,它可以通过将bean属性名称与列名匹配来填充列表中的对象(注意,这个类是为了方便而不是性能)。
当您需要的结果不仅仅是一个简单的列表时,RowCallbackHandler
会更有用。你必须自己管理返回对象,你正在使用这种方法。当我需要一个地图结构作为我的返回类型时(例如,对于树表的分组数据或者如果我基于主键创建自定义缓存),我通常会发现自己使用它。
当您想要控制结果的迭代时,使用ResultSetExtractor
。您将实现一个方法extractData
,该方法将是query
调用的返回值。我只发现自己使用这个,如果我必须构建一些使用其他任何一个回调接口构建起来更复杂的自定义数据结构。
queryForList()
方法很有价值,因为您不必实现这些回调方法。使用queryForList有两种方法。第一种情况是,如果您只查询数据库中的单个列(例如字符串列表),则可以使用以Class作为参数的方法版本自动为您提供这些类的对象列表。
调用queryForList()
的其他实现时,您将获得一个列表,每个条目都是每列的映射。虽然这很好,因为您节省了编写回调方法的费用,但处理这种数据结构非常笨拙。由于地图的值为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框架的非常好的部分。最重要的是,我会说尝试用每种方法编写一些代码,看看哪种方法最适合你。
答案 1 :(得分:3)
由于您处于奇妙的泛型领域,您可能真正想要做的是使用SimpleJdbcTemplate
并使用query()
方法来Lists
个对象和queryForObject()
对于个别对象。对此的推理仅仅是因为它们比JdbcTemplate
中的那些更容易使用。
答案 2 :(得分:2)
上面优秀答案的一小部分补充:如果你正在运行一个简单的查询并期望单行,那么其他方法(如queryForInt,queryForLong,queryForMap,queryForObject等)有时可能看起来不错。
但是,如果您可以返回0或1行,则queryForList方法通常更容易,否则您必须捕获IncorrectResultSizeDataAccessException。我学到了很难的方法。