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

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

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

Re[9]: トランザクションの状態の判定


(過去ログ 10 を表示中)

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

■1535 / inTopicNo.1)  トランザクションの状態の判定
  
□投稿者/ 緑茶庵 (1回)-(2007/02/27(Tue) 14:35:19)

分類:[C# (Windows)] 

DBのトランザクションに関するご質問です。

開発環境:VisualStadio2005(.NET2.0), WindowsXP
使用言語:C#

DBTransaction クラスを使用して
トランザクションの管理をしておりますが
DBへの処理途中でエラーで終了や意図的に終了した場合に(未COMMIT状態)
必ずRollBack処理を行う良い方法はありますでしょうか?

現在、下記の例のように
boolのフラグを設けて無理やり判定を行っておりますが
フラグを使わずにもう少しスッキリとした方法を探しております。

他言語ですが、DelphiのDB接続を管理するオブジェクト(TDataBase)の
InTransactionメソッド(トランザクション中の判定)のような
メソッドがDBTransactionにあれば・・と思ったのですが

DBTransaction クラスのメンバには
トランザクション中かどうかを判定するメソッド・プロパティは
無いようでした・・

よろしくお願いいたします。

-------例-------------------------------
*コネクションは既に存在するとする

//トランザクションの開始
using (DBTransaction trans = コネクション.BeginTransaction())
{
    //トランザクション判定フラグ初期化
    bool transFlg = false;
    try
        //////////////
        //DBへの処理(DML)//
        //省略//
        //////////////

        //コミット
        trans.Commit;

        //トランザクション判定フラグをtrue(コミット完了)に変更する
        transFlg = true;
    }
    finally
    {
        //トランザクション判定フラグがfalse(未コミット)の場合はロールバックする
        if (!transFlg)
        {
            trans.RollBack();
        }
    }
}
    
-----------------------------------






引用返信 編集キー/
■1537 / inTopicNo.2)  Re[1]: トランザクションの状態の判定
□投稿者/ HIRO (4回)-(2007/02/27(Tue) 14:49:49)
HIRO さんの Web サイト
2007/02/27(Tue) 14:51:29 編集(投稿者)

No1535 (緑茶庵 さん) に返信
> DBへの処理途中でエラーで終了や意図的に終了した場合に(未COMMIT状態)

エラー発生時のRollBackなら
catchの中で行えば良いのではないでしょうか?

tryに対応するcatchが無いのは何か意図していますか?

下記はVB.NETですが参考になるかと思います
http://www.microsoft.com/japan/msdn/thisweek/step7/ADONET_Transaction/
引用返信 編集キー/
■1572 / inTopicNo.3)  Re[2]: トランザクションの状態の判定
□投稿者/ 緑茶庵 (2回)-(2007/02/27(Tue) 17:31:58)
No1537 (HIRO さん) に返信
> 2007/02/27(Tue) 14:51:29 編集(投稿者)
> 
> ■No1535 (緑茶庵 さん) に返信
>>DBへの処理途中でエラーで終了や意図的に終了した場合に(未COMMIT状態)
> 
> エラー発生時のRollBackなら
> catchの中で行えば良いのではないでしょうか?
> 
> tryに対応するcatchが無いのは何か意図していますか?
> 
> 下記はVB.NETですが参考になるかと思います
> http://www.microsoft.com/japan/msdn/thisweek/step7/ADONET_Transaction/

HIRO さん ご返信をありがとうございます。

catch を使用しなかったのは例外発生時以外に
意図的に終了する場合があるためでした。

try
    //DML文処理1(省略)

    int execCount = コマンド.execNonQuery();

    if (execCount == 0)
    {
        MessageBox.Show("更新件数が0件のため処理を中止します");
        return;
    }

    //DML文処理2(省略)

    //コミット
    trans.Commit();
finally
{
    //ロールバック処理(省略)
}


ただ、この処理のようにCommitを行う前にreturnを行った場合でも
DBConnectionのお陰なのか、実際にDBへの更新は行われませんでした。

finallyでロールバック処理を書いたのは
保険の意味あいがとても強く、Commitしていない処理は
とにかく全てロールバック処理を行いたかったからです。

*return の前にロールバックを書いても良いかも知れませんが
 書き忘れもあるのでやりたくありません


commitせずに且つcatch を通らない処理を行う場合は
普通どうされているのでしょうか?
ロールバックを書かないのが普通なのでしょうか?
逆に catch句では遭えてロールバックを行っているので
ロールバックを行わないのは不安です。。

勉強不足で申し訳ございませんが
よろしくお願いいたします。




引用返信 編集キー/
■1577 / inTopicNo.4)  Re[3]: トランザクションの状態の判定
□投稿者/ HIRO (5回)-(2007/02/27(Tue) 18:07:14)
HIRO さんの Web サイト
No1572 (緑茶庵 さん) に返信
> catch を使用しなかったのは例外発生時以外に
> 意図的に終了する場合があるためでした。

 これはどのようなときを意味するのでしょうか?

> ただ、この処理のようにCommitを行う前にreturnを行った場合でも
> DBConnectionのお陰なのか、実際にDBへの更新は行われませんでした。

 Comnmitをしていないのですから更新されないのは当然だと思います。
 でなければTransactionの意味がないですよね?


> finallyでロールバック処理を書いたのは
> 保険の意味あいがとても強く、Commitしていない処理は
> とにかく全てロールバック処理を行いたかったからです。
>
> *return の前にロールバックを書いても良いかも知れませんが
>  書き忘れもあるのでやりたくありません

 return で処理を抜けるのであればfinalyには到達しませんよね?
 であれば、その前にロールバック処理をするべきではないでしょうか?

returnで処理を抜けない場合は、つまりexecCountが0より大きい場合はCommitされるときですよね?
 この場合は例外が発生しなければロールバックの必要が無いので、保険でfinallyにロールバック処理を入れる必要は内容に思えます。
(例外の発生を考えるとcatchは必要だと思います)

引用返信 編集キー/
■1578 / inTopicNo.5)  Re[4]: トランザクションの状態の判定
□投稿者/ すけけん (15回)-(2007/02/27(Tue) 18:19:07)
すけけん さんの Web サイト
No1577 (HIRO さん) に返信
> ■No1572 (緑茶庵 さん) に返信
>>finallyでロールバック処理を書いたのは
>>保険の意味あいがとても強く、Commitしていない処理は
>>とにかく全てロールバック処理を行いたかったからです。
>>
>>*return の前にロールバックを書いても良いかも知れませんが
>> 書き忘れもあるのでやりたくありません
>
>  return で処理を抜けるのであればfinalyには到達しませんよね?
>  であれば、その前にロールバック処理をするべきではないでしょうか?
>
> returnで処理を抜けない場合は、つまりexecCountが0より大きい場合はCommitされるときですよね?
>  この場合は例外が発生しなければロールバックの必要が無いので、保険でfinallyにロールバック処理を入れる必要は内容に思えます。
> (例外の発生を考えるとcatchは必要だと思います)

return文でもbreak文でもfinallyは有効ですよ。
http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_018/csharp_abc03.html
引用返信 編集キー/
■1579 / inTopicNo.6)  Re[4]: トランザクションの状態の判定
□投稿者/ 未記入 (35回)-(2007/02/27(Tue) 18:54:06)
No1577 (HIRO さん) に返信
>  return で処理を抜けるのであればfinalyには到達しませんよね?
>  であれば、その前にロールバック処理をするべきではないでしょうか?

finallyが何のためにあるのかわかってないようですね。

finally句が実行されないのは、Applicationが強制的に落とされた時などです。
あとはスレッドAbortか。
引用返信 編集キー/
■1580 / inTopicNo.7)  Re[5]: トランザクションの状態の判定
□投稿者/ HIRO (6回)-(2007/02/27(Tue) 19:12:54)
HIRO さんの Web サイト
すけけんさん、未記入さん、ありがとうございました。

全くその通りです。
自環境にて確認致しました。
お恥ずかしい限りです。
引用返信 編集キー/
■1582 / inTopicNo.8)  Re[6]: トランザクションの状態の判定
□投稿者/ HIRO (7回)-(2007/02/27(Tue) 21:51:24)
HIRO さんの Web サイト
finally の件大変失礼しました。

以下のように例外をスローさせ、catchで処理をするというのはどうでしょう?

try
{
    // 省略

    if (execCount == 0)
    {
        //catchで受け取れるよう例外をスロー
        throw new Exception("更新件数が0件のため処理を中止します"); 
        return;
    }

    //Commit処理
    trans.Commit();
      
}
catch ( Exception ex )
{
    // ロールバック処理
    trans.RollBack();
}

引用返信 編集キー/
■1591 / inTopicNo.9)  Re[7]: トランザクションの状態の判定
□投稿者/ まさる (1回)-(2007/02/28(Wed) 10:21:07)
2007/02/28(Wed) 10:52:11 編集(投稿者)
はじめまして。まさると申します。

■No1582 (HIRO さん) に返信
> finally の件大変失礼しました。
> 
> 以下のように例外をスローさせ、catchで処理をするというのはどうでしょう?
> 
> try
> {
>     // 省略
> 
>     if (execCount == 0)
>     {
>         //catchで受け取れるよう例外をスロー
>         throw new Exception("更新件数が0件のため処理を中止します"); 
>         return;
>     }
> 
>     //Commit処理
>     trans.Commit();
>       
> }
> catch ( Exception ex )
> {
>     // ロールバック処理
>     trans.RollBack();
> }

これだと例外を握りつぶしてしまっているため、危険な実装ですよ。

明示的に発生させた例外ならば、

try
{
    // 処理1

    if ( 条件 )
    {
        throw new ApplicationException("〜");
    }

    // 処理2
}
catch ( ApplicationException apex )
{
    // ロールバック処理
    trans.RollBack();

    // 想定された例外の処理
    MessageBox.Show(apex.Message);
}
catch ( Exception )
{
    // ロールバック処理
    trans.RollBack();

    // 発生した例外をthrow
    throw;
}

のようにしたほうが良いのではないでしょうか。

#ただ、明示的にRollBackしなくとも、Commitしていなければ、
#usingステートメントを抜ける際(もしくはDisposeが呼ばれた際)に
#自動的にRollBackされるので、それでよい気がしますが。

引用返信 編集キー/
■1596 / inTopicNo.10)  Re[8]: トランザクションの状態の判定
□投稿者/ HIRO (8回)-(2007/02/28(Wed) 12:17:19)
HIRO さんの Web サイト
2007/02/28(Wed) 12:20:42 編集(投稿者)

No1591 (まさる さん) に返信
>
> これだと例外を握りつぶしてしまっているため、危険な実装ですよ。
>
ごもっともです。
示した例が悪かったですね。

確かに、私が示したコードでは、明示的に発生させた例外か、そうでないのかを判断することはできません。
ApplicationExceptionは「デザインしているアプリケーションで固有の例外を作成する必要がある場合」に使用すると
ヘルプ(http://msdn2.microsoft.com/ja-jp/library/system.applicationexception(VS.80).aspx)にありますので、まさるさんが示してくれた例がよいかもしれません。
引用返信 編集キー/
■1597 / inTopicNo.11)  Re[9]: トランザクションの状態の判定
□投稿者/ HIRO (10回)-(2007/02/28(Wed) 12:18:16)
HIRO さんの Web サイト
2007/02/28(Wed) 12:21:34 編集(投稿者)

間違って同じ内容を送信してしまったので削除します
引用返信 編集キー/
■1610 / inTopicNo.12)  Re[9]: トランザクションの状態の判定
□投稿者/ 緑茶庵 (3回)-(2007/02/28(Wed) 17:06:23)
No1596 (HIRO さん) に返信
> 2007/02/28(Wed) 12:20:42 編集(投稿者)
>
> ■No1591 (まさる さん) に返信
>>
>>これだと例外を握りつぶしてしまっているため、危険な実装ですよ。
>>
> ごもっともです。
> 示した例が悪かったですね。
>
> 確かに、私が示したコードでは、明示的に発生させた例外か、そうでないのかを判断することはできません。
> ApplicationExceptionは「デザインしているアプリケーションで固有の例外を作成する必要がある場合」に使用すると
> ヘルプ(http://msdn2.microsoft.com/ja-jp/library/system.applicationexception(VS.80).aspx)にありますので、まさるさんが示してくれた例がよいかもしれません。

ご返信をありがとうございます。

例外をスローさせて全てcatchするやり方にすれば
とりあえずやりたい事に近いことはできそうです。
(解決とさせていただきます)

ただ、処理を抜けたい部分への
例外をスローさせる処理を書き忘れた場合は
catch を通らないので・・不安です。
(そのために当初は finally に書こうとしていたのですが)


解決済み
引用返信 編集キー/
■1611 / inTopicNo.13)  Re[8]: トランザクションの状態の判定
□投稿者/ 緑茶庵 (4回)-(2007/02/28(Wed) 17:15:30)
No1591 (まさる さん) に返信
> 2007/02/28(Wed) 10:52:11 編集(投稿者)

>
> #ただ、明示的にRollBackしなくとも、Commitしていなければ、
> #usingステートメントを抜ける際(もしくはDisposeが呼ばれた際)に
> #自動的にRollBackされるので、それでよい気がしますが。

前の方の投稿でも書かせていただきましたが
自環境においてRollBackを明示しなくとも
自動的にRollBackがかかっていたようでした。

これが、DBTransactionのDisposeが行っているのかどうか
調べましたが見つけることもできず確証を得られませんでしたが
usingを使っていれば、まさるさんが仰るとおりRollBackしなくとも
良さそうですね。

ただ、そうすると catchの中でもRollBackを書かなくても良いのでは?
とも思いますが・・・例外発生時は敢えてRollBackが必要なのでしょうか。。

そうなると、DBTransactionオブジェクトの解放をしっかりやっていても
やはり処理中のRollBackは明示したほうが良いのでしょうか。



引用返信 編集キー/
■1613 / inTopicNo.14)  Re[9]: トランザクションの状態の判定
□投稿者/ 未記入 (37回)-(2007/02/28(Wed) 17:26:39)
Rollbackメソッドは明示的に書いておくべきですよ。
将来(ありえないとは思うけど)Disposeの挙動がそのままである保証もないですし、明示的でないとコードから仕様が伝わってきません。
引用返信 編集キー/
■1615 / inTopicNo.15)  Re[10]: トランザクションの状態の判定
□投稿者/ 緑茶庵 (5回)-(2007/02/28(Wed) 17:39:03)
No1613 (未記入 さん) に返信
> Rollbackメソッドは明示的に書いておくべきですよ。
> 将来(ありえないとは思うけど)Disposeの挙動がそのままである保証もないですし、明示的でないとコードから仕様が伝わってきません。

ご返信をありがとうございます。

仰るとおりです。今後もRollBackメソッドは明示したいと思います。
解決済み
引用返信 編集キー/
■1619 / inTopicNo.16)  Re[9]: トランザクションの状態の判定
□投稿者/ まさる (2回)-(2007/02/28(Wed) 18:13:33)
No1611 (緑茶庵 さん) に返信
> これが、DBTransactionのDisposeが行っているのかどうか
> 調べましたが見つけることもできず確証を得られませんでしたが
> usingを使っていれば、まさるさんが仰るとおりRollBackしなくとも
> 良さそうですね。

SqlTransactionの場合は下記のエントリが参考になります。
 「河端善博の .TEXT でウェブログ:SqlTransaction.Dispose は、Rollback 処理を含む」
  ttp://blogs.sqlpassj.org/yoshihirokawabata/archive/2005/12/29/15218.aspx

ただ、未記入さんの仰るように、コードより仕様を読み取りやすくするためにも、
明示的に呼び出したほうが良いですね。

混乱させてしまい申し訳ありませんでした。
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -