我可以在读取数据时中断数据读取器吗
本文关键字:读取 数据 中断 我可以 | 更新日期: 2023-09-27 18:21:28
是否可以停止正在运行的读取器?
场景:我有一个包含100000个数据集的表
CREATE TABLE stock (
uid bigint NOT NULL,
name text,
quantity integer,
x bytea,
y bytea
);
以及用于读取数据的控制台应用程序(.NET 4.0,Npgsql 2.0.11.0/2.0.11.92)
conn = new NpgsqlConnection("Server=localhost;Database=postgres;User id=postgres;password=postgres;Timeout=600;CommandTimeout=600;ConnectionLifeTime=600;");
using (new ConnectionOpen(conn))
using (var ta = conn.BeginTransaction(IsolationLevel.Snapshot))
{
IDbCommand command = conn.CreateCommand("SELECT * from stock;");
command.SetTransaction(ta);
IDataReader reader = command.ExecuteReader();
int n = 0;
while (!reader.IsClosed && reader.Read())
{
n++;
if (n > 5000)
{
if (reader != null)
{
((NpgsqlDataReader)reader).Close();
}
}
}
((NpgsqlDataReader)reader).Dispose();
reader = null;
}
我观察到数据阅读器真的停不下来。数据读取器似乎先读取所有行,然后正常返回。
这个例子是一个更大的应用程序的摘要,用户将通过按下按钮来停止数据读取器,因为读取时间太长。
我知道这个线程相当古老,但我相信这个人的问题的正确答案如下:
command.Cancel(); //execute before closing the reader
reader.Close();
通过调用DbCommand.Cancel(),您指示不应再处理任何记录,并且命令(包括底层查询)应立即停止并快速退出。如果您不取消该命令,当您试图关闭DbDataReader(或脱离循环/使用块),并且您正在处理大量返回的记录时,close()方法会填充输出参数、返回值和RecordsAffected的值。
如果您试图在读卡器读取所有记录之前关闭它,那么close会尝试读取所有数据并填写这些值,它看起来只是挂起(很可能会引发某种超时异常)。如果您不关心结果集中的剩余值——如果您正在脱离读取循环,则很可能不关心——那么应该在调用Close()之前取消底层命令。
上述部分信息检索自:https://www.informit.com/guides/content.aspx?g=dotnet&seqNum=610
您可以在while循环中插入一个break,但不确定是否/如何将其与用户操作联系起来,让他们决定何时退出读取循环。或者,您可以重组代码,使其返回第一个x行数,然后给它们一个继续按钮,以返回其余行数或返回下一个x行。
数据读取器通常从数据库服务器返回大块数据(至少它与SQL server是这样工作的)。PostgreSQL可能会有不同的表现。
另一种攻击方法是将数据加载为后台任务(BackgroundWorker、task等)。这样,你的UI线程就可以保持响应,阅读器是如何实现的也无关紧要。
这只是猜测。
可能的解决方案1
...
using (var ta = conn.BeginTransaction(IsolationLevel.Snapshot))
{
IDbCommand command = conn.CreateCommand("SELECT * from stock;");
command.SetTransaction(ta);
IDataReader reader = command.ExecuteReader();
int n = 5000;
//put it in using
using(IDataReader reader = command.ExecuteReader())
{
//read first N rows
for(int i=0;i<n;i++)
{
//get value from the columns of the current row
for (i = 0; i < reader.FieldCount; i++)
{
Console.Write("{0} 't", reader[i]);
}
}
}
}
可能的解决方案2
使用TOP
sql命令,请参阅示例