28

現在 Oracle と連携していますが、MS SQL のソリューションも必要になります。

ユーザーがデータベースで実行される SQL を生成できるようにする GUI があります。生成される検索によっては、これには非常に長い時間がかかる場合があります。この検索中に GUI/アプリを応答させ、ユーザーが検索をキャンセルできるようにしたい。

バックグラウンド ワーカー スレッドを使用しています。

私の問題は、ユーザーが検索をキャンセルしたときに、データベースへの呼び出しを中断できないことです。完了するまで待機してから、「CancelationPending」プロパティをポーリングできます。これはデータベースのリソースを浪費するだけでなく、コードに問題を引き起こします。

ユーザーが非常に長いクエリで [検索] をクリックし、[キャンセル] をクリックしてからもう一度 [検索] をクリックした場合、最初の検索はまだデータベースで処理されています。バックグラウンド ワーカーは、検索を再度実行してもまだビジー状態です。この問題に対する唯一の解決策は、新しいバックグラウンド ワーカーを作成することです。

それは物事を行うための本当に醜い方法のようです。データベースは動作し続けます バックグラウンドワーカーの新しいインスタンスを作成しています....データベース呼び出しを本当に停止して同じワーカーを再利用したいとき。

どうやってやるの?

4

11 に答える 11

10

ADO.NET と SQL データ プロバイダーを使用している場合は、SqlCommand.Cancel メソッドをご覧ください。それはあなたが探していることをします。ただし、キャンセルしようとするとキャンセルに時間がかかる場合があります。基本的に、いつキャンセル要求を許可するかは、SQL Server によって決定されます。クエリがキャンセルされると、操作がユーザーによってキャンセルされたことを示す SqlException を取得する必要があります。どうやら、この例外を例外として扱い、ユーザーが操作をキャンセルしたために SqlException が発生した場合などに特別に処理したくない場合は、そのまま飲み込んでください。

于 2009-05-20T17:36:18.190 に答える
8

また、command.Cancel()が実際にコマンドを中止しないことに気づきました。私にとってうまくいったのは、ユーザーが中止したときに接続を閉じることです(使用する場合はロールバックトランザクション)。これにより、コマンドの実行中にバックグラウンドスレッドで例外が発生するため、コマンドをキャッチしてそこでCancellationPendingプロパティを確認し、その場合は例外を再スローしないようにする必要があります...

// When aborting
worker.CancelAsync();
command.Connection.Close();

// In your DoWork event handler
...
catch (Exception)
{
    if (worker.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
    else
    {
        throw;
    }
}

// And in your RunWorkerCompleted event handler
if (e.Error == null && !e.Cancelled)
{
    ...
}
于 2010-09-13T10:02:34.883 に答える
5

これが可能であると確信しています。TOADforOracleを使用しており、ここで説明するように、実行時間の長いクエリをキャンセルできます。しかし、彼らがそれをどのように行うのかはわかりません。

于 2009-05-21T17:02:53.820 に答える
3

最善の解決策は、監視テーブルを介してセッションを強制終了することだと思います。

Oracleを使用すると、Burnsysが言うように作成できます

Firebird 2.5 では同じように見えます

Ms SQLにも同様のものが存在することを願っています

于 2009-05-20T19:45:04.077 に答える
3

バックグラウンドワーカーに別のスレッドで実際のデータベース呼び出しを開始させ、データベース呼び出しが終了したか、キャンセルが押されたかを定期的に確認し、その時点でデータベーススレッドを強制終了することができます。これは実際にはデータベースのロードには役立ちませんが (クエリが送信され、まだ処理中であるため)、それに関連するローカル リソースは解放されます。

于 2009-05-20T17:09:01.770 に答える
2

SQLCommand を使用している場合は、そのCancelメソッドを呼び出してみてください。

于 2009-05-20T17:17:47.790 に答える
2

データベースへの新しい接続を開き、sysdba としてログインし、終了するプロセスの SID を指定して「ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE」コマンドを送信します。

sessionID を取得するには、rownum = 1 の v$mystat から sid を選択します。

Serial# を取得するには: v$session から sid, serial# を選択します。ここで、sid = :SID

http://www.oracle-base.com/articles/misc/KillingOracleSessions.php

編集:ここでsysdbaとしてログインしないためのWWのアイデア: http://forums.oracle.com/forums/thread.jspa?threadID=620578

于 2009-05-20T17:19:07.350 に答える
1

ADO 2.8 と SQLOLEDB または SQL Server ネイティブ クライアントでキャンセルとクローズの両方を試しました。Cancel を使用すると、レコードセットはデータのフェッチを停止しますが、バックラウンドではサーバーからの読み取りが続行され、アプリケーションのメモリが消費されます。32 ビット アプリケーションでは、数分後に「メモリ不足」メッセージが表示されることがあります。レコードセット (または、キャンセルの有無にかかわらず接続) を閉じると、ADO 2.8 はすべてのレコードがフェッチされるまで待機します。

ADO.NET の方が優れているかどうかはわかりませんが、キャンセル/クローズ後にメモリとネットワーク アクセスを監視して、ADO が実際にデータの読み取りを停止していることを確認することをお勧めします。

于 2012-05-23T09:16:03.473 に答える
-2

私はそれが可能だとは思わない。このトピックに関する Oracle の Web サイトでのディスカッションへのリンクは次のとおりです

于 2009-05-20T17:06:45.893 に答える