7

実行中のリーダーを停止することは可能ですか?

シナリオ: 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;
}

データ リーダーが実際に停止できないことを確認しました。データリーダーは最初にすべての行を読み取り、その後正常に戻るようです。

この例は、読み取りに時間がかかりすぎるためにユーザーがボタンを押してデータ リーダーを停止する、より大きなアプリケーションの要約です。

4

4 に答える 4

9

このスレッドがかなり古いことは承知していますが、この人の質問に対する正しい答えは次のとおりだと思います。

command.Cancel(); //execute before closing the reader
reader.Close();

DbCommand.Cancel() を呼び出すことで、これ以上レコードを処理する必要がなく、コマンド (基になるクエリを含む) をすぐに停止してすぐに終了する必要があることを示しています。コマンドをキャンセルせずに DbDataReader を閉じようとした場合 (またはループ/using ブロックから抜け出そうとした場合)、返される多数のレコードを処理している場合、Close() メソッドは出力パラメータ、戻り値、および RecordsAffected の値。

すべてのレコードを読み取る前にリーダーを閉じようとすると、Close はすべてのデータを読み取ってそれらの値を入力しようとするため、ハングしているように見えます (おそらく、何らかのタイムアウト例外がスローされます)。結果セットの残りの値を気にしない場合 (読み取りループから抜け出す場合は気にしない可能性が高い) は、Close() を呼び出す前に基になるコマンドをキャンセルする必要があります。

上記の情報の一部は、https ://www.informit.com/guides/content.aspx?g=dotnet&seqNum=610 から取得されました。

于 2014-08-07T21:17:57.383 に答える
0

whileループを中断することはできますが、それをユーザーアクションに関連付けて、読み取りループをいつ中断するかをユーザーに決定させるかどうか/どのように行うかはわかりません。または、コードを再構築して、最初のx行を返し、続行ボタンを押して残りを返すか、次のx行を返すようにすることもできます。

于 2012-01-25T16:02:41.933 に答える
0

これは推測です。

考えられる解決策 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

TOPsql コマンドを使用します。サンプルを参照してください

于 2012-01-25T16:07:48.660 に答える
0

通常、データ リーダーは、データベース サーバーからデータのチャンクを返します (少なくとも、SQL Server ではそのように動作します)。Postgre SQL は内部で異なる動作をする場合があります。

これを攻撃する別の方法は、バックグラウンド タスク ( BackgroundWorkerTaskなど)としてデータの読み込みを行うことです。そうすれば、UI スレッドの応答性が維持され、リーダーが内部でどのように実装されているかは問題になりません。

于 2012-01-25T16:19:45.417 に答える