C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: ODPを介したSQLコマンドのキャンセルについて


(過去ログ 95 を表示中)

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■56503 / inTopicNo.1)  ODPを介したSQLコマンドのキャンセルについて
  
□投稿者/ hanayama (1回)-(2011/01/17(Mon) 15:15:24)

分類:[.NET 全般] 

ODPを介したSQLコマンドのキャンセルについて質問がございます。

■開発環境
Windowsアプリケーション
言語:VB.NET (.NET Framework 1.1)
ORACLEバージョン:ORACLE 9i
ORACLEとのインタフェース:ODP.NET

現在、SQLの問い合わせ(SELECT文)を中止するためのボタンを
フォームに持たせたいと考えています。
(ORACLEからの応答が遅い場合に、ユーザから自由にコマンドを中断させたい)

フォーム上のボタンを押下可能にしなければならないため、
クエリを別スレッドで発行しようと考えていますが、
そもそも、SQLコマンドの発行後の中止が出来るのかどうか
色々と情報をあさってはいますが、答えにたどり着けないでいます。

もし、ご存知の方が居られましたら、ご教授下さい。
よろしくお願いします。

※捕捉
下記のサイトで、「OracleCommand.Cancel」について記述があったので、
サンプルコードをVB用に変えて試しましたが、コマンドのキャンセルはされませんでした。
OracleCommand.ExecuteReaderインスタンスを取得後に、Readメソッドを呼び出すところで、
処理待ち状態になり、キャンセルはもちろんのこと、結果的に非同期での
コマンド実行もできていない状態に思えます。
http://otndnld.oracle.co.jp/document/products/oracle10g/102/windows/B31247-01/OracleCommandClass.htm#DAFIEHHG


引用返信 編集キー/
■56504 / inTopicNo.2)  Re[1]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ マサヤ (217回)-(2011/01/17(Mon) 15:58:00)
2011/01/17(Mon) 15:58:49 編集(投稿者)

BackgroundWorkerを使用したらいかがでしょうか?
http://www.labasp.net/CsharpNote/mControl/BackgroundWorker/101_110.html
引用返信 編集キー/
■56512 / inTopicNo.3)  Re[2]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ オショウ (574回)-(2011/01/17(Mon) 18:54:48)
> BackgroundWorkerを使用したらいかがでしょうか?

  いや、それではダメで・・・
  非同期コマンドを使わないとキャンセルできないかと。

  ADO.NETにも非同期コマンドがあります。
  http://msdn.microsoft.com/ja-jp/library/dd229379.aspx#ado2featurematrix_topic3

  ODP.NETにもあるようですので、それを試してください。

以上。参考まで
引用返信 編集キー/
■56518 / inTopicNo.4)  Re[3]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ hanayama (3回)-(2011/01/18(Tue) 09:10:41)
No56512 (オショウ さん) に返信
>>BackgroundWorkerを使用したらいかがでしょうか?
>
>   いや、それではダメで・・・
>   非同期コマンドを使わないとキャンセルできないかと。
>
>   ADO.NETにも非同期コマンドがあります。
>   http://msdn.microsoft.com/ja-jp/library/dd229379.aspx#ado2featurematrix_topic3
>
>   ODP.NETにもあるようですので、それを試してください。
>
> 以上。参考まで

 マサヤさん、オショウさん
 迅速な回答ありがとうございます。

 間違っていましたら、申し訳ございません。
 開発環境ですが、.NET Framework 1.1限定のため、BeginExecuteReader等の
 2.0以降の非同期コマンドが使用できないように思えます。


引用返信 編集キー/
■56521 / inTopicNo.5)  Re[4]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ マサヤ (220回)-(2011/01/18(Tue) 10:01:56)
http://msdn.microsoft.com/ja-jp/library/system.data.oracleclient.oracledatareader.close%28v=VS.71%29.aspx
OracleDataReader.Closeは使用できないでしょうか?
引用返信 編集キー/
■56523 / inTopicNo.6)  Re[1]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ shu (366回)-(2011/01/18(Tue) 11:33:21)
No56503 (hanayama さん) に返信

> OracleCommand.ExecuteReaderインスタンスを取得後に、Readメソッドを呼び出すところで、
> 処理待ち状態になり、キャンセルはもちろんのこと、結果的に非同期での
ExecuteReaderは完了しているのでしょうか?
Readは1レコード読むだけなのでこのメソッドにそんなに時間がかかるとは思えないのですが
ExecuteReaderとReadの間で何か処理をされていますでしょうか?
引用返信 編集キー/
■56524 / inTopicNo.7)  Re[2]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ hanayama (4回)-(2011/01/18(Tue) 12:00:41)
No56523 (shu さん) に返信
> ■No56503 (hanayama さん) に返信
>
>>OracleCommand.ExecuteReaderインスタンスを取得後に、Readメソッドを呼び出すところで、
>>処理待ち状態になり、キャンセルはもちろんのこと、結果的に非同期での
> ExecuteReaderは完了しているのでしょうか?
> Readは1レコード読むだけなのでこのメソッドにそんなに時間がかかるとは思えないのですが
> ExecuteReaderとReadの間で何か処理をされていますでしょうか?
 
 shuさん
 
 説明不足でした。申し訳ございません。

 完了はします。「while(ExecuteReader.Read())」によって、
 数万レコード分読み取るのですが、
 最初のループ時に(最初に呼び出されるExecuteReader.Read())数十秒の
 処理待ち状態となります。(このときにクエリが発行されて、サーバーとの同期を取っているのでしょうか?)
 以降のループは特に処理待ちという感じはしません。
 
 そもそも、これは非同期になっていないということですよね。


 マサヤさん

 OracleDataReader.Closeを使用するというのは、
 コマンドが非同期で実行されていることが前提になりますでしょうか?
 もしくは、マルチスレッドでコマンド実行したスレッドとは
 別のスレッドから、OracleDataReader.Close(むしろConnection.Close?)を呼び出すイメージでしょうか?
 いまいち、使用方法がわからず・・・申し訳ないです。

以上
 
 

引用返信 編集キー/
■56527 / inTopicNo.8)  Re[3]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ shu (367回)-(2011/01/18(Tue) 12:23:05)
No56524 (hanayama さん) に返信

>  完了はします。「while(ExecuteReader.Read())」によって、

OracleCommand cmd = 〜;
OracleDataReder rd = cmd.ExecuteReader();

while (rd.Read()){


ということでよろしいでしょうか?
これで最初のReadを実行するのに時間がかかっているとすると
OracleConnection自体を閉じてしまうしかないような気がします。
あとは多分Exception出るのでTryで拾うとかですかね。
引用返信 編集キー/
■56528 / inTopicNo.9)  Re[4]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ マサヤ (221回)-(2011/01/18(Tue) 12:42:10)
IAsyncResultでコールバックを受け取って、そこで処理したらいいかと思いました。
delegateに中止処理を登録する形になるから同一スレッド?

読み込み処理に何秒以上かかったらキャンセルという閾値があれば、そこで判定できると思います。
引用返信 編集キー/
■56532 / inTopicNo.10)  Re[5]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ hanayama (6回)-(2011/01/18(Tue) 13:16:30)
No56528 (マサヤ さん) に返信
> IAsyncResultでコールバックを受け取って、そこで処理したらいいかと思いました。
> delegateに中止処理を登録する形になるから同一スレッド?
>
> 読み込み処理に何秒以上かかったらキャンセルという閾値があれば、そこで判定できると思います。

 マサヤさん

 IAsyncResultでコールバックを受け取るというのは、
 .NET 1.1のODPでは可能なのでしょうか?
 また、「キャンセル」というのは中止処理のdelegateが呼び出されたタイミングで、
 OracleCommand.Cancelを呼び出すイメージでしょうか?

 
shuさん
 
 はい。その使用方法と同一です。「while (rd.Read())」に入ったタイミングで、
 処理待ちとなるため、別スレッド(キャンセル用)から同一のOracleConnectionの
 Connectionを切るイメージでしょうか?


 ご協力ありがとうございます。
 質問ばかりで、大変心苦しいです。
 
 

引用返信 編集キー/
■56551 / inTopicNo.11)  Re[1]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ todo (96回)-(2011/01/18(Tue) 19:10:46)
> フォーム上のボタンを押下可能にしなければならないため、
> クエリを別スレッドで発行しようと考えていますが、
> そもそも、SQLコマンドの発行後の中止が出来るのかどうか
> 色々と情報をあさってはいますが、答えにたどり着けないでいます。

SqlCommand.Cancel メソッド
http://msdn.microsoft.com/ja-jp/library/system.data.sqlclient.sqlcommand.cancel(v=vs.71).aspx

に別スレッドでExecuteReaderとCancelを行うサンプルがあります。
SqlServer相手に試したところ SqlDataReader.Readで
「ユーザーによって操作がキャンセルされました。」
という例外になりました。
ODPに書き換えて試してみては?
引用返信 編集キー/
■56556 / inTopicNo.12)  Re[2]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ hanayama (7回)-(2011/01/19(Wed) 13:24:46)
No56551 (todo さん) に返信
>>フォーム上のボタンを押下可能にしなければならないため、
>>クエリを別スレッドで発行しようと考えていますが、
>>そもそも、SQLコマンドの発行後の中止が出来るのかどうか
>>色々と情報をあさってはいますが、答えにたどり着けないでいます。
> 
> SqlCommand.Cancel メソッド
> http://msdn.microsoft.com/ja-jp/library/system.data.sqlclient.sqlcommand.cancel(v=vs.71).aspx
> 
> に別スレッドでExecuteReaderとCancelを行うサンプルがあります。
> SqlServer相手に試したところ SqlDataReader.Readで
> 「ユーザーによって操作がキャンセルされました。」
> という例外になりました。
> ODPに書き換えて試してみては?

ご回答ありがとうございます。

ご提示頂いた、ページのサンプルをODP用(.NET 1.1)に変えて確認しました。
何度か試しましたが(キャンセル時のSleepの時間変更や発行するSQL文を変え)
「ユーザーによって操作がキャンセルされました。」の例外は発生せず、
「キャンセルされた」ことが確認できませんでした。
処理上は、コマンド用スレッドの「Do While r.Read」中に、
キャンセル用スレッドの「_cmd.Cancel()」が呼び出されているのですが。

※ちなみにOracleCommand用の同メソッドの下記ページのサンプルでは
とてもコマンドがキャンセルされる気がしないです・・・
http://msdn.microsoft.com/ja-jp/library/system.data.oracleclient.oraclecommand.cancel%28v=vs.71%29.aspx


念のためODP用に変えたソースを載させて頂きます。
コンソールアプリケーションのMainメソッド(MTAThread)から、
下記ソースの「CancelTest()」を呼び出して確認しています。
------------------------------------------------------------------------
    Private _cmd As OracleCommand
    Private _e1 As AutoResetEvent = New AutoResetEvent(False)
    Private _e2 As AutoResetEvent = New AutoResetEvent(False)

    Public Sub IssueQuery()
        Dim r As OracleDataReader
        Dim rows As Integer = 0
        Try
            r = _cmd.ExecuteReader()
            Do
                Do While r.Read
                    rows = rows + 1
                Loop
            Loop While r.NextResult()
            Console.WriteLine("FAILED: execution should not have finished, {0} rows read!", rows)
        Catch
            Console.WriteLine("PASSED:  Got expected exception!")
        End Try
        _e1.Set()
    End Sub

    Public Sub CancelQuery()
        System.Threading.Thread.Sleep(100)
        _cmd.Cancel()
        _e2.Set()
    End Sub

    Public Sub CancelTest()
        Dim conn As OracleConnection = New OracleConnection("接続文字列")
        conn.Open()
        _cmd = New OracleCommand("", conn)

        Dim evs() As AutoResetEvent = {_e1, _e2}

        Dim t1Start As ThreadStart = New ThreadStart(AddressOf IssueQuery)
        Dim t2Start As ThreadStart = New ThreadStart(AddressOf CancelQuery)
        Dim t1 As Thread = New Thread(t1Start)
        Dim t2 As Thread = New Thread(t2Start)

        ' cancel operation while results are coming back
        _cmd.CommandText = "SELECT文"(結果セット取得まで約1分)
        t1.Start()
        t2.Start()
        WaitHandle.WaitAll(evs)
        conn.Close()

    End Sub

------------------------------------------------------------------------

引用返信 編集キー/
■56562 / inTopicNo.13)  Re[3]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ todo (98回)-(2011/01/19(Wed) 19:30:54)
Cancelは駄目みたいですね。
conn.Closeはどうでしょう?
引用返信 編集キー/
■56570 / inTopicNo.14)  Re[4]: ODPを介したSQLコマンドのキャンセルについて
□投稿者/ hanayama (8回)-(2011/01/20(Thu) 09:29:52)
No56562 (todo さん) に返信
> Cancelは駄目みたいですね。
> conn.Closeはどうでしょう?

todoさん

ご回答ありがとうございます。
サンプルコードの「_cmd.Cancel()」を
「_cmd.Connection.Close()」に変更し、確認させていただきました。
結果的に、「 Do While r.Read」の箇所で、
NullReferenceExceptionが発生しました。

ただし、実行するSQL文(重さ)によって上記例外の発生タイミングが
異なりました。また、SQL発行中にCloseをするのと
しないのとではOracleの応答時間の差がほとんどありませんでした。
そのため、「キャンセル」というイメージではありません。
(conn.Close()直後のOracle上のセッションもACTIVE状態)

理想としてはCloseのタイミングでわりかし早めに
例外が発生し、(かつNullReference以外)
メインスレッドに処理が返ってくれるといいのですが・・・

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -