いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

OracleでTransactionScopeを使用する際の注意点 (System.Data.OracleClient.OracleConnection, oramts, TransactionScope)

Oracle(10gR2)でTransactionScopeを利用する際に、以下のエラーがでる場合があります。

"oramts.dllが見つかりません。"

このエラーが出た場合、以下の点を疑ってみてください。

マシンに、Oracle Services For Microsoft Transaction Service (OraMTS)がインストールされているかどうか?

OraMTSは、Oracle Clientをカスタムモードでインストールしないとインストールされません。
インストールすると、ORACLE_HOME/Binの下に以下のファイルが見つかります。

  • oramts.dll
  • oramts10.dll

このファイルが無いと、TransactionScopeブロック内でコネクションをOpenした時に落ちます。
逆に言うとこのファイルさえあれば動きます。
また、TransactionScopeブロックの外でコネクションをOpenし、そのコネクションを使用して
TransactionScope内で処理を行なっても、うまく動きますが、これは実はトランザクション
参加していません。なので、処理が失敗し、TransactionScope.Completeメソッドが呼ばれない
状態だと通常ロールバックされるはずが、ロールバックされない状態となります。
具体的には、以下のようなコードの場合です。

[TestFixture()]
public class TestClass{

    OracleConnection _conn;

    [Setup()]
    public void SetUpMethod(){
        _conn = new OracleConnection("Data Source=xxx;User Id=xxx;Password=xxx;Enlist=True");
    }

    [TearDown()]
    public void TearDownMethod(){
        _conn.Close();
    }

    [Test()]
    public void TestMethod(){
        using(TransactionScope tx = new TransactionScope()){
            using(OracleCommand command = _conn.CreateCommand()){
                command.CommandText = "insert into xxx (xxx) values (xxxx)";
                
                Assert.AreEqual(1, command.ExecuteNonQuery());

                tx.Complete();
            }
        }
    }
}

上記のコードの場合、例えば一意制約などで追加処理が失敗した場合、Completeメソッドは
よばれないままブロックを抜けますが、ロールバックはされません。しかも、この場合は
TransactionScopeクラスが管理するトランザクションに参加しないので、oramts.dllが
存在しない状態でも動作します。つまり、OraMTSがインストールされていない状態でも
見た目ちゃんと動いているように見えます。(これにハマリました・・・)