SqlDataAdapter 与 SqlDataReader
Posted
技术标签:
【中文标题】SqlDataAdapter 与 SqlDataReader【英文标题】:SqlDataAdapter vs SqlDataReader 【发布时间】:2009-11-04 21:30:06 【问题描述】:使用 从数据库获取数据有什么区别?
我正在专门研究它们的优缺点以及它们的速度和内存性能。
谢谢
【问题讨论】:
【参考方案1】:数据读取器:
需要保持连接打开直到完成(不要忘记关闭它!)。 通常只能迭代一次 对于更新回数据库没有那么有用另一方面,它:
内存中一次只有一条记录,而不是整个结果集(这可能巨大) 在一次迭代中几乎可以达到最快速度 允许您更快地开始处理结果(一旦第一条记录可用)。对于某些查询类型,这也可能非常重要。数据适配器/数据集
让您在加载数据完成后立即关闭连接,甚至可以自动为您关闭它 所有结果都在内存中可用 您可以根据需要对其进行多次迭代,甚至可以按索引查找特定记录 具有一些用于更新回数据库的内置功能代价是:
更多更高的内存使用率 您要等到所有数据都加载完毕后再使用任何数据所以这真的取决于你在做什么,但我倾向于更喜欢 DataReader,直到我需要仅由数据集支持的东西。 SqlDataReader 非常适合绑定到只读网格的常见数据访问案例。
有关详细信息,请参阅the official Microsoft documentation。
【讨论】:
DataSet 是内存中的数据存储,而 datareader 只是检索数据的媒介。顺便说一句,您可以在 DataSet 上运行 Linq 查询,但不能在 datareader 上运行。 实际上,通过一些额外的代码,您当然可以在数据读取器上运行 linq 查询(或至少一个查询)。只需使用迭代器块在while (reader.Read())
循环中将 DataReader 强制转换为 IDataRecord 即可。
这个答案具有误导性。如果您使用“使用”语句包装 SqlConnection 和 SqlDataReader 对象(无论如何您都应该这样做,因为它们是 IDisposable),连接将自动关闭。您可以将 DataSet 与 SqlDataReader 一起使用:只需调用 DataSet.Load(SqlDataReader)。
@RickNZ 不要太快相信使用语句为您关闭事情。他们调用对象的 Dispose() 方法,而不是 Close() 方法,并且我遇到了至少一种情况,即 Dispose 并没有真正为我关闭对象。最好在 using 块中包含对 close 方法的显式调用。
@Cdaragorn MSDN 文档通常非常清楚 Close() 与 Dispose()。例如,在 SqlConnection 的情况下,文档说 Close() 和 Dispose() 在功能上是等效的。我对调用 Close() 没有任何异议,但对所有 IDisposables 也应该调用 Dispose() —— 最简洁的方法是使用 using 语句。如果你知道 Dispose() 不会调用 Close(),那么你应该尽可能在 finally 块中调用 Close(),而不是在 using 块中(所以如果出现异常,它仍然会被调用)。跨度>
【参考方案2】:
这个问题的答案可能相当广泛。
本质上,对我而言,通常会影响我使用哪个决定的主要区别在于,使用 SQLDataReader,您可以从数据库中“流式传输”数据。使用 SQLDataAdapter,您可以将数据库中的数据提取到一个对象中,该对象本身可以进一步查询,并对其执行 CRUD 操作。
显然,对于数据流,SQLDataReader 的速度要快得多,但您一次只能处理一条记录。使用 SQLDataAdapter,您可以从数据库中获得与查询匹配的行的完整集合,以使用/传递您的代码。
警告:如果您使用的是 SQLDataReader,请始终、始终、始终确保编写正确的代码来关闭连接,因为您使用 SQLDataReader 保持连接打开。如果不这样做,或在处理结果时发生错误时关闭连接的正确错误处理将CRIPPLE您的应用程序连接泄漏。
请原谅我的 VB,但这是您在使用 SqlDataReader 时应该拥有的最少代码量:
Using cn As New SqlConnection("..."), _
cmd As New SqlCommand("...", cn)
cn.Open()
Using rdr As SqlDataReader = cmd.ExecuteReader()
While rdr.Read()
''# ...
End While
End Using
End Using
等效的 C#:
using (var cn = new SqlConnection("..."))
using (var cmd = new SqlCommand("..."))
cn.Open();
using(var rdr = cmd.ExecuteReader())
while(rdr.Read())
//...
【讨论】:
如果您的目标是在 db 上使用 select 查询获取数据,并且只在不同的行访问这些数据,转到 rpevious 行等,那么您可以使用 SQLDatareader 并将其加载到数据表中使用 dtable.Load(rdr)。然后在此数据表中上下浏览。您可以使用此方法代替 DataAdapter...【参考方案3】:SqlDataAdapter 通常用于填充 DataSet 或 DataTable,因此您可以在连接关闭后访问数据(断开访问)。
SqlDataReader 是一个快速只进且连接的游标,通常比填充 DataSet/DataTable 更快。
此外,使用 SqlDataReader,您可以一次处理一条数据,并且不会在内存中保存任何数据。显然,对于 DataTable 或 DataSet,您确实有内存分配开销。
如果您不需要将数据保存在内存中,那么仅用于渲染内容,请使用 SqlDataReader。如果您想以断开连接的方式处理数据,请选择 DataAdapter 来填充 DataSet 或 DataTable。
【讨论】:
【参考方案4】:想要从数据库中填充内存中的 DataSet/DataTable 时,请使用 SqlDataAdapter。然后,您可以灵活地关闭/处理连接,在内存中传递数据表/集。然后,您可以使用数据适配器以及 InsertCommand/UpdateCommand 操作数据并将其持久化回 DB。
当需要快速、低内存占用的数据访问而不需要灵活性时使用 SqlDataReader,例如围绕业务逻辑传递数据。这对于大数据量的快速、低内存使用检索更为优化,因为它不会一次性将所有数据加载到内存中 - 使用 SqlDataAdapter 方法,DataSet/DataTable 将填充所有数据,所以如果有很多行和列,需要大量内存来保存。
【讨论】:
【参考方案5】:Fill 函数在内部使用 DataReader。如果您的考虑是“哪个更有效?”,那么在逐条记录填充集合的紧密循环中使用 DataReader 可能与使用 DataAdapter.Fill 对系统的负载相同。
(System.Data.dll、System.Data.Common.DbDataAdapter、FillInternal。)
【讨论】:
以上是关于SqlDataAdapter 与 SqlDataReader的主要内容,如果未能解决你的问题,请参考以下文章
SqlDataAdapter 与 SqlDataReader
C# SqlDataAdapter 与来自多个数据库的表的 JOIN
C# SqlDataAdapter 与来自多个数据库的表的 JOIN