none
BeginTransactionが破棄されるまでの数瞬の動きについて RRS feed

  • 質問

  • 下記ソースにてご指摘ください。

    環境:VS2015

    MVC5 スキャフォールディング機能を利用 リポジトリ、インタフェースを実装

            Using tx = _db.Database.BeginTransaction
                Try

                    (DBへの処理 A)

            _db.SaveChanges()

              (DBへの処理 B)

            _db.SaveChanges()

                   (DBへの処理 C)     

            _db.SaveChanges()  

                    'コミット
                    Call tx.Commit()
                    Return True
                Catch ex As Exception
                    'ロールバック
                    Call tx.Rollback()
                    Return False
                End Try

            End Using

            【【【 Aのテーブルからデータを取得】】】

    ご教示いただきたいのは、Aのテーブルからデータを取得するのに、DBコンテキストを利用しているのですが

    時々、Execution Timeout Expired.  だとか

    Object reference not set to an instance of an object. というメッセージが出て

    値が正しく取得できていません。

    よくよく調べてみると、End Usingの時点で、

    インタフェースで実装している  Inherits IDisposable より

    リポジトリクラスで実装している下記の自動生成されたソースが動き、DBコンテキストを破棄しているみたいです

    (違っていたらご指摘ください)

    #Region "IDisposable Support"
        Private disposedValue As Boolean ' 重複する呼び出しを検出するには

        ' IDisposable
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not disposedValue Then
                If disposing Then
                    ' TODO: マネージ状態を破棄します (マネージ オブジェクト)。
                End If

                ' TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下の Finalize() をオーバーライドします。
                ' TODO: 大きなフィールドを null に設定します。
                _db.Dispose()
                _db = Nothing
            End If
            disposedValue = True
        End Sub

        ' TODO: 上の Dispose(disposing As Boolean) にアンマネージ リソースを解放するコードが含まれる場合にのみ Finalize() をオーバーライドします。
        Protected Overrides Sub Finalize()
            ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(disposing As Boolean) に記述します。
            Dispose(False)
            MyBase.Finalize()
        End Sub

        ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
        Public Sub Dispose() Implements IDisposable.Dispose
            ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(disposing As Boolean) に記述します。
            Dispose(True)
            ' TODO: 上の Finalize() がオーバーライドされている場合は、次の行のコメントを解除してください。
            GC.SuppressFinalize(Me)
        End Sub

    #End Region

    聞きたいのは、EndUsingで破棄がすぐされるのであれば、直後のAのテーブルから値の取得は出来ないと思うのですが、

    これは、EndUsingによりDisposeされるまでの数瞬は破棄されておらず有効であったとか

    そういうことなのでしょうか?

    ご教示いただければ幸いです。

    2017年4月28日 10:13

回答

  • 聞きたいのは、EndUsingで破棄がすぐされるのであれば、直後のAのテーブルから値の取得は出来ないと思うのですが、これは、EndUsingによりDisposeされるまでの数瞬は破棄されておらず有効であったとかそういうことなのでしょうか?

    まったくの見当違いです。

    Call tx.Commit()が完了した時点で書き込みは完了し、ロック解除されます。Disposeによるコネクション破棄のタイミングとは無関係です。

    挙げられたコードだけでは何が起きているかは不明確ですが、「Execution Timeout Expired.」に関してはあるトランザクションの実行に時間を要し、そのトランザクションの完了を待つ別のトランザクションがタイムアウトした可能性があります。
    「Object reference not set to an instance of an object.」に関してはオブジェクトインスタンスがforループの途中で破棄される事があると同じく挙げられている範囲のコードでは何が起きているのか特定できません。

    …というようにとにかく情報が足りません。

    • 回答としてマーク rururururu 2017年5月1日 4:30
    2017年4月28日 22:54

すべての返信

  • 聞きたいのは、EndUsingで破棄がすぐされるのであれば、直後のAのテーブルから値の取得は出来ないと思うのですが、これは、EndUsingによりDisposeされるまでの数瞬は破棄されておらず有効であったとかそういうことなのでしょうか?

    まったくの見当違いです。

    Call tx.Commit()が完了した時点で書き込みは完了し、ロック解除されます。Disposeによるコネクション破棄のタイミングとは無関係です。

    挙げられたコードだけでは何が起きているかは不明確ですが、「Execution Timeout Expired.」に関してはあるトランザクションの実行に時間を要し、そのトランザクションの完了を待つ別のトランザクションがタイムアウトした可能性があります。
    「Object reference not set to an instance of an object.」に関してはオブジェクトインスタンスがforループの途中で破棄される事があると同じく挙げられている範囲のコードでは何が起きているのか特定できません。

    …というようにとにかく情報が足りません。

    • 回答としてマーク rururururu 2017年5月1日 4:30
    2017年4月28日 22:54
  • 質問者さんが立てた前のスレッド:

    オブジェクトインスタンスがforループの途中で破棄される事がある
    https://social.msdn.microsoft.com/Forums/ja-JP/3b656d73-9a3c-44e2-8381-03c3c160dba9/for?forum=vbgeneralja

    で、

    > コードの詳細内容が不明なので単なる想像ですが・・・

    >> Catch ex As Exception

    > Exception を catch しているので例外が発生してもなかったことになってしまうという
    > ことが怪しそうな気がします。

    > ・・・中略・・・

    > 最初に書きましたが単なる想像ですので、Exception をキャッチは今回の問題の原因とし
    > てはハズレかもしれません。ただし、Exception をキャッチするのは止めた方がいいのは
    > 確かなようですので、それが原因ではなくても直した方がよさそうです。

    と書いたのですが、そのことは考慮されているのでしょうか?

    2017年4月29日 3:07
  • 佐祐理様

    忙しい中お返事ありがとうございます。

    call.tx.commit()についての、詳細な説明や

    情報が足りない中でヒントもご提示していただきありがとうございます。

    WEBにあげた後では極稀に、

    localhostでステップ実行してテストしていた際には高頻度(100%ではない)

    ことから、ありえるのかな、、、とか考えてしまっていたのですが、

    そもそも意味を取り違えていたようです。

    違うということがわかっただけでも助かりました。ありがとうございます。

    2017年5月1日 4:30
  • SurferOnWww様

    前回に引き続き、貴重なお時間をいただきご回答ありがとうございます。

    前回ご指摘いただいた後、すぐさまスルーを追加し、Exceptionを消したのですが、

    今回の質問に反映されておりませんでした。

    >>質問者さんのコードではロールバックするために Exception を catch しているようですが、ロールバックしたら即例外を再スローしたらどうなりますか?

    エラー発生頻度が低く、まだ2回ぐらいしか見えていないのですが、エラー文言等は変わったようには見えませんでした。

    ヒントをいただけているのに有用な事を言えず申し訳ございません。

    2017年5月1日 4:43