Cancel
このメソッドは、特定の接続で現在実行されているコマンドの取消しを試みます。
宣言
// C# public override void Cancel();
実装
IDbCommand.Cancel
備考
コマンドが正しく取り消された場合は、例外がスローされます。正しく取り消されない場合、例外はスローされません。Cancelの起動時に実行中のコマンドがない場合、Cancelは何も実行しません。Cancelメソッドを起動しても、その時点で実行されているコマンドが常に取り消されることが保証されるわけではありません。実行が終了する前にその実行が完了する場合があります。このような場合、例外はスローされません。
コマンドを取り消すと、コマンド実行ステージ、または結果フェッチ・ステージ(問合せの場合)が停止します。これらのステージが完了している場合、Cancelは何も実行しません。
管理対象のODP.NETまたはODP.NET CoreによってCancelが呼び出される場合は確定的です。つまり、OracleCommandオブジェクトによって実行されたコマンドは、取り消すことができる唯一のコマンドであることを意味します。管理対象外のODP.NETのCancelは非確定的です。
管理対象外のODP.NETにおける非確定的とは、複数のOracleCommandオブジェクトが同一接続を共有する場合に、その接続で一度に実行できるのは1つのコマンドのみであることを意味します。Cancelメソッドは、起動されると、OracleCommandオブジェクトがコマンドの実行に使用している接続上で現在実行されている文を取り消そうとします。ただし、複数のOracleCommandオブジェクトが同じ接続上で同時に文を実行している場合は、Cancelメソッドを起動すると、発行済のコマンドが取り消される可能性があります。これは、Cancelの起動が有効になる前に取消を指示したコマンドが完了する可能性があるためです。これが発生した場合、別のOracleCommandによって実行されるコマンドが、かわりに取り消される可能性があります。
Cancelメソッドが原因となるこの不確定な状況を回避するには、次のようないくつかの方法があります。
-
アプリケーションで各接続に
OracleCommandオブジェクトを1つのみ作成できます。これにより、特定の接続を使用するOracleCommandオブジェクトで実行されるコマンドのみが、Cancelの起動によって確実に取り消されます。 -
アプリケーション内でのコマンドの実行は、同じ接続を使用する
OracleCommandオブジェクト間で同期化することができます。
Cancelがアプリケーションで使用されない場合、前述の内容は適用されません。
現在の実行がいつ終了するかは不明確であるため、非原子的なSQLまたはPL/SQLの実行はトランザクション内で開始することをお薦めします。コマンドの実行が例外ORA-01013: user requested cancel of current operationで正しく終了した場合、トランザクションをロールバックしてデータの整合性を保つことができます。コマンドの取消が発生した場合、他の例外としてORA-00936およびORA-00604がスローされることがあります。非原子的な実行の例としては、1つずつ実行されるDMLコマンドのコレクションや、PL/SQLのストアド・プロシージャまたは関数の一部である複数のDMLコマンドなどがあります。
例
// C#
// This example shows how command executions can be cancelled in a
// deterministic way even if multiple commands are executed on a single
// connection. This is accomplished by synchronizing threads through events.
// Since the Cancel method terminates the currently running operation on the
// connection, threads must be serialized if multiple threads are using the
// same connection to execute server round-trip incurring operations.
// Furthermore, the example shows how the execution and cancel threads should
// be synchronized so that nth iteration of the command execution does not
// inappropriately cancel the (n+1)th command executed by the same thread.
using System;
using System.Data;
using Oracle.DataAccess.Client;
using System.Threading;
class CancelSample
{
private OracleCommand cmd;
Thread t1, t2;
// threads signal following events when assigned operations are completed
private AutoResetEvent ExecuteEvent = new AutoResetEvent(false);
private AutoResetEvent CancelEvent = new AutoResetEvent(false);
private AutoResetEvent FinishedEvent = new AutoResetEvent(false);
AutoResetEvent[] ExecuteAndCancel = new AutoResetEvent[2];
// Default constructor
CancelSample()
{
cmd = new OracleCommand("select * from all_objects",
new OracleConnection("user id=scott;password=tiger;data source=oracle"));
ExecuteAndCancel[0] = ExecuteEvent;
ExecuteAndCancel[1] = CancelEvent;
}
// Constructor that takes a particular command and connection
CancelSample(string command, OracleConnection con)
{
cmd = new OracleCommand(command, con);
ExecuteAndCancel[0] = ExecuteEvent;
ExecuteAndCancel[1] = CancelEvent;
}
// Execution of the command
public void Execute()
{
OracleDataReader reader = null;
try
{
Console.WriteLine("Execute.");
reader = cmd.ExecuteReader();
Console.WriteLine("Execute Done.");
reader.Close();
}
catch(Exception e)
{
Console.WriteLine("The command has been cancelled.", e.Message);
}
Console.WriteLine("ExecuteEvent.Set()");
ExecuteEvent.Set();
}
// Canceling of the command
public void Cancel()
{
try
{
// cancel query if it takes longer than 100 ms to finish execution
System.Threading.Thread.Sleep(100);
Console.WriteLine("Cancel.");
cmd.Cancel();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Cancel done.");
Console.WriteLine("CancelEvent.Set()");
CancelEvent.Set();
}
// Execution of the command with a potential of cancelling
public void ExecuteWithinLimitedTime()
{
for (int i = 0; i < 5; i++)
{
Monitor.Enter(typeof(CancelSample));
try
{
Console.WriteLine("Executing " + this.cmd.CommandText);
ExecuteEvent.Reset();
CancelEvent.Reset();
t1 = new Thread(new ThreadStart(this.Execute));
t2 = new Thread(new ThreadStart(this.Cancel));
t1.Start();
t2.Start();
}
finally
{
WaitHandle.WaitAll(ExecuteAndCancel);
Monitor.Exit(typeof(CancelSample));
}
}
FinishedEvent.Set();
}
[MTAThread]
static void Main()
{
try
{
AutoResetEvent[] ExecutionCompleteEvents = new AutoResetEvent[3];
// Create the connection that is to be used by three commands
OracleConnection con = new OracleConnection("user id=scott;" +
"password=tiger;data source=oracle");
con.Open();
// Create instances of CancelSample class
CancelSample test1 = new CancelSample("select * from all_objects", con);
CancelSample test2 = new CancelSample("select * from all_objects, emp",
con);
CancelSample test3 = new CancelSample("select * from all_objects, dept",
con);
// Create threads for each CancelSample object instance
Thread t1 = new Thread(new ThreadStart(test1.ExecuteWithinLimitedTime));
Thread t2 = new Thread(new ThreadStart(test2.ExecuteWithinLimitedTime));
Thread t3 = new Thread(new ThreadStart(test3.ExecuteWithinLimitedTime));
// Obtain a handle to an event from each object
ExecutionCompleteEvents[0] = test1.FinishedEvent;
ExecutionCompleteEvents[1] = test2.FinishedEvent;
ExecutionCompleteEvents[2] = test3.FinishedEvent;
// Start all threads to execute three commands using a single connection
t1.Start();
t2.Start();
t3.Start();
// Wait for all three commands to finish executing/canceling before
//closing the connection
WaitHandle.WaitAll(ExecutionCompleteEvents);
con.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}関連項目:
-
Oracle.DataAccess.ClientおよびOracle.ManagedDataAccess.Clientのネームスペース
-
このMicrosoft .NET Framework 機能の詳細は、
http://msdn.microsoft.com/libraryを参照