ResultSet 与 RowSet:选择哪一个以及何时选择?

Posted

技术标签:

【中文标题】ResultSet 与 RowSet:选择哪一个以及何时选择?【英文标题】:ResultSet vs RowSet: Which one to choose and when? 【发布时间】:2011-09-29 18:54:55 【问题描述】:

所以我知道一些相对差异,即ResultSet 具有与数据库的“开放连接”,而RowSet 以“断开连接”方式工作。

但这就是我所理解的(可能不正确):

那么我的问题是——在什么情况下一种比另一种更可取?他们各自的优势/劣势是什么?

从我的感觉是RowSet,在 断开模式尤其适用于 “只读”查询,会有 在高度更好的表现 并发系统。那是对的吗? 如果是这样的话,可以放心地说 RowSet 总是比 ResultSet 用于只读查询?

如果我正确地迭代 RowSet 不会抛出 SQL 异常, 但这有好处吗?另一个 因为RowSet 是可序列化的。 但我的担忧主要来自于 绩效观点会是什么 选择?

但这是否重要 读写查询??可以同步吗 ResultSet 回到 DB? (我不是 确定这是否可能(可能是 我就是不记得或谷歌 它足够好:) 已经有一段时间了 使用原始 JDBC...

有什么想法吗?很明显,我的知识存在一些缺失的空白:)

我问的原因是我想在处理一些数据时在实现 Spring-JDBC 的 ResultSetExtractor 接口与返回 SqlRowSet 之间进行选择。这个问题只是让我好奇如何决定何时选择什么,而不是扔硬币:)

【问题讨论】:

【参考方案1】:

行集

RowSet 几乎总是正确的选择,它功能更全面,并具有您列出的所有优点以及用于特殊目的的专门实现,例如断开连接的CachedRowSet,这是我在处理数据时总是使用的将适合内存,因此我可以尽快将连接释放回池以供重用。

ResultSet 绝不应该成为公共合同的一部分。

连接的ResultSet/Rowset 永远不应该逃避方法,或者最坏的情况是创建它们的对象。至少使用RowSet,您可以断开它并且客户端不必关心实现。 *除非您正在编写与 ResultSet 特定功能或合同交互或依赖的 JDBC 特定库代码。

如果您只是传输查询结果,JDBC 特定类应该是您的公共合同的一部分。

理想情况下,您希望将 RowSet/ResultSet 内容具体化为类型安全的域对象以进行传递。

在大多数情况下,您希望实现域对象的 List/Set 以进行操作和使用,而不是将您的代码直接耦合到 JDBC api。

许多现代的ResultSetMapper<T> 类存在使用Visitor 模式来处理生成类型安全域实例,因为这是惯用的做事方式。

【讨论】:

当一些遗留的第三方 API 需要它作为方法的输入时。【参考方案2】:

我不同意 JR 的回答。 RowSet 通常是一个不错的选择,但与往常一样,最佳答案取决于您的情况和您的需求。对所有内容使用 RowSet 不会产生功能失调的代码,但它可以提供比 ResultSet 更慢的性能(常见的 JdbcRowSet 实现是 ResultSet 的包装器)。

如果您需要在需要 JavaBean 的模块化代码中使用结果对象,那么 RowSet 满足 Java Bean 的最低要求。

如果您正在为多线程/服务器应用程序开发代码,那么您必须接受所有 Java Bean 都是可变的,因此不是线程安全的。因此,Resultset 和 RowSet 都不是线程安全的。

如果您编写的代码使用数据库查询并将它们转换为 Java 数据模型对象以供应用程序的其余部分使用,那么 RowSet 的性能可能不如结果集。

在我编写的许多代码中,当我收到一个 JDBC 数据库查询时,我一直在简单地使用结果集将检索到的行立即处理成一个数据模型对象列表。结果集甚至无法在执行翻译的方法调用中幸存下来。在我看来,这很好......因为Resultsets(以及RowSets)消耗大量资源,并且您希望它们尽快可用于gc。

在这种模式下,我什至不需要结果集的任何新功能,更不用说行集了。我只是在集合中向前迭代一次并生成结果行列表。

在某些情况下,非常需要行集。由于 RowSet 是可序列化的并且表面上是“轻量级的”,因此断开连接的 CachedRowSet(例如)代表了一种在位置之间传输数据库查询结果的相当有效的机制,特别是如果您希望数据可以就地更新。当然,您也可以序列化和传输对象列表。

【讨论】:

连接的 ResultSets 永远不应该逃避创建它们的方法,或者在更糟糕的情况下是拥有它们的对象,因此它们永远不应该成为公共 api 的一部分。 如果您不提供 getters 并使所有实例引用 private final 并且引用的对象是不可变的,那么所有 JavaBeans 都是可变的,那么并发很容易。 @JarrodRoberson “所有 JavaBeans 都不是可变的......” ...我必须不同意。当然,您可以通过初始化 JavaBean 对象并确保其状态永远不会改变来有效地完成...但是...您将如何做到这一点?您可以通过将线程安全状态机作为 JavaBean 类的一部分来实现,或者通过创建字段final 使 JavaBean 模拟一个不可变类(如您所建议的)来实现。在前一种情况下,仍然可以观察到处于不一致状态的类实例……而在后一种情况下,您实际上并没有 JavaBean。 自 2005 年左右以来,符合标准的 "JavaBeans" 就不再是任何人真正关心的问题,更不用说在 2013 年编写此答案时,尤其是在 2018 年及以后。它们在创建时是个坏主意,并且很快就实现了。很明显,即使在 3 年前,不可变数据结构的好处多于负面,并且是首选的设计选择。现在,当人们说 JavaBean 时,他们真的是卑鄙的 POJO、无参数构造函数、getter/setter JavaBean 一致性近 15年。

以上是关于ResultSet 与 RowSet:选择哪一个以及何时选择?的主要内容,如果未能解决你的问题,请参考以下文章

在使用 JDBC 的 DAO 类中,哪一个是处理关闭 ResultSet、PreparedStatement 和 Connection 的 try-catch 的最佳方法?

以原子方式更新多行

如何在 Zend 中使用表上的子查询执行查询并获取 Rowset 对象作为结果?

笔记本电脑双显卡 - 如何以编程方式检测和/或选择使用哪一个

选择 stackView 上的哪个子视图将拉伸(以编程方式)

为啥插入和选择查询的结果集不同