質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.09%

MySQLのデータ更新でInvalidOperationExceptionエラー

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,141

kirinsan

score 7

バージョン情報

MySQL 5.0.77
SQLServer2012
ASP.net(.NET Framework 4)

発生している問題・エラーメッセージ

SQLServerからMySQLへ、データ同期をとるために
複数テーブルに対して、

  1. MySQLデータのdelete
  2. SQLServerのselect
  3. MySQLへinsert(select件数分)

の3ステップによりデータの更新を行っていますが
運用して数年経った今、途中でエラーが発生するようになってしまいました。

System.InvalidOperationException: Connection must be valid and open to rollback transaction

このエラーに対する対処法を探しています。

同じデータで試しても開発環境では発生しない現象なので、環境設定に依存するのかと思い
MySQLにて「timeout」に関する設定を確認してみたのですが、いずれの環境でも以下のような設定になっており、差異が見つけられませんでした。

Variable_name  Value
connect_timeout 10
delayed_insert_timeout 300
innodb_lock_wait_timeout 50
innodb_rollback_on_timeout OFF
interactive_timeout 28800
net_read_timeout 30
net_write_timeout 60
slave_net_timeout 3600
table_lock_wait_timeout 50
wait_timeout 28800

よろしくお願いします。

=== 追記 ===
ソースは以下のように記述しています。

Dim SE As New clsDbAccess
Dim MySqlSE As New clsMySqlAccess

'***** MySql接続設定開始 *****
MySqlSE.ConnectionString = "接続文字列"
MySqlSE.CommandTimeout = CommandTimeout

'### トランザクション
MySqlSE.BeginTransaction()
'***** MySql接続設定終了 *****

'### 接続コネクション設定(SqlServer)
SE.ConnectionString = "接続文字列"
SE.CommandTimeout = CommandTimeout

'### トランザクション
SE.BeginTransaction()

'
'SQLServerに対する更新処理
'~~
'

'SQLServer⇒MySQLへのデータ流し込み

''deleteその1
strSQL = "DELETE FROM tableA_MySQL WHERE ~"

MySqlSE.CommandString = strSQL
MySqlSE.ExecuteTSQL()

''selectその1
strSQL = "SELECT * FROM tableB_SQLServer WHERE ~"

SE.TableName = "RESULT"
SE.CommandString = strSQL
SE.ExecuteSQL()

Dim DT_TMP As DataTable = Nothing
DT_TMP = SE.TableData.Tables(SE.TableName)

For i = 0 To DT_TMP.Rows.Count - 1
    ''insertその1
    strSQL = " INSERT INTO tableC_MySQL (~) VALUES (~) "

    MySqlSE.CommandString = strSQL
    MySqlSE.ExecuteTSQL()
Next

''deleteその2
strSQL = "DELETE FROM tableD_MySQL WHERE ~"

MySqlSE.CommandString = strSQL
MySqlSE.ExecuteTSQL()

''selectその2
strSQL = "SELECT * FROM tableE_SQLServer WHERE ~"

SE.TableName = "RESULT"
SE.CommandString = strSQL
SE.ExecuteSQL()

Dim DT_TMP As DataTable = Nothing
DT_TMP = SE.TableData.Tables(SE.TableName)

For i = 0 To DT_TMP.Rows.Count - 1
    ''insertその2
    strSQL = " INSERT INTO tableF_MySQL (~) VALUES (~) "

    MySqlSE.CommandString = strSQL
    MySqlSE.ExecuteTSQL()
Next

''deleteその3
strSQL = "DELETE FROM tableG_MySQL WHERE ~"

MySqlSE.CommandString = strSQL
MySqlSE.ExecuteTSQL()

''selectその3
strSQL = "SELECT * FROM tableH_SQLServer WHERE ~"

SE.TableName = "RESULT"
SE.CommandString = strSQL
SE.ExecuteSQL()

Dim DT_TMP As DataTable = Nothing
DT_TMP = SE.TableData.Tables(SE.TableName)

For i = 0 To DT_TMP.Rows.Count - 1
    ''insertその3
    strSQL = " INSERT INTO tableI_MySQL (~) VALUES (~) "

    MySqlSE.CommandString = strSQL
    MySqlSE.ExecuteTSQL()
Next

'### コミット(SqlServer)
SE.Commit()

'### コミット(MySql)
MySqlSE.Commit()




'' クラス定義
Public Class clsMySqlAccess
    Public Function ExecuteTSQL() As Boolean

        'トランザクションが開始されているかどうか
        If _sqlTransaction Is Nothing Then
            OpenConnection()
            _sqlCommand = New MySqlCommand(_commandString, _sqlConnection)
            _sqlCommand = _sqlConnection.CreateCommand

            _sqlCommand.CommandTimeout = _commandTimeout
        Else
            _sqlCommand = New MySqlCommand(_commandString, _sqlConnection)
            _sqlCommand.Transaction = _sqlTransaction
            _sqlCommand.CommandTimeout = _commandTimeout
        End If

        _executeCount = _sqlCommand.ExecuteNonQuery()

        If _sqlTransaction Is Nothing Then
            CloseConnection()
        End If

        Return True

    End Function
End Class

Public Class clsDbAccess
    Public Function ExecuteSQL() As Boolean

        Dim DS As New DataSet()

        'トランザクションが開始されているかどうか
        If _sqlTransaction Is Nothing Then
            OpenConnection()
            _sqlDataAdapter = New System.Data.SqlClient.SqlDataAdapter()
            _sqlDataAdapter.SelectCommand = New System.Data.SqlClient.SqlCommand(_commandString, _sqlConnection)
            _sqlDataAdapter.SelectCommand.CommandTimeout = _commandTimeout
        Else
            _sqlDataAdapter = New System.Data.SqlClient.SqlDataAdapter()
            _sqlDataAdapter.SelectCommand = New System.Data.SqlClient.SqlCommand(_commandString, _sqlConnection)
            _sqlDataAdapter.SelectCommand.Transaction = _sqlTransaction
            _sqlDataAdapter.SelectCommand.CommandTimeout = _commandTimeout
        End If

        'DataSetにSelect結果を格納
        _sqlDataAdapter.Fill(DS, _tableName)
        _executeCount = DS.Tables(0).Rows.Count

        _tableData = DS

        If _sqlTransaction Is Nothing Then
            CloseConnection()
        End If

        Return True

    End Function
End Class
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2019/02/13 07:41 編集

    意図せずクローズされてしまうところが問題ではないかと言っているのですが。話を理解していただいているでしょうか。

    キャンセル

  • SurferOnWww

    2019/02/13 07:54

    VB.NET, SQL Server などのタグを追加した方がよさどうです。ASP.NET では注目度が低そうなので。

    キャンセル

  • kirinsan

    2019/02/13 11:34

    タグを変更いたしました。
    意図せずクローズされているところがないか、デバッグで確認できるとよいのですが
    開発環境では再現しないため検証できていない状態です。
    環境次第で動作が異なるため、設定まわりによる原因なのではないかと思い、差異等を調べていましたが発見に至らずこちらで質問させていただいています。

    キャンセル

回答 1

0

MySQLのバージョンが古いのが気になりますね。
現象を再現できる最低限のコードを提示した方が適切なコメントが付き易いです。
エラー・メッセージでググると、
>System.InvalidOperationException: Connection must be valid and open to rollback transaction

InvalidOperationException during Transaction Rollback

[12 Aug 2009 17:29] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

 http://lists.mysql.com/commits/80702

パッチが提供されているようです。MySQLはオラクル社に回収されたからサポート契約が必要かも?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/12 21:27

    コードを追記いたしました。
    確かに古すぎてMySQL Installerも存在していませんね・・今まで数年分の動作実績があることと
    本番機のバージョンアップは気軽に行えないことより、バージョンアップは最終手段として考えていきたいと思います。
    ありがとうございます。

    キャンセル

  • 2019/02/13 06:03

    コードが省略され過ぎていてわかりませんが、INSERT ... SELECT に直せればバグが回避できるかも?お使いのMySQLのバージョンで使えるかわかりません。
    https://dev.mysql.com/doc/refman/5.6/ja/insert-select.html
    どちらにしてもバージョンが古過ぎて、機関銃で戦っている横で火縄銃を構えているようなのものですから、本当にシステムが止まってしまっても構わいならともかく、きちんと費用を確保してMySQLのバージョンアップをスケジュールに入れましょう。

    キャンセル

  • 2019/02/13 11:49

    対応OSの問題もありますので、長い目で見てバージョンアップは対応予定ですが
    どんなに速くても数ヶ月先になってしまうと思いますので、直近で何とかする方法があればと思っています。
    クエリ内容はあまり重要ではないと思って省略してしまいましたが、細かく記載することによって分かることもあるでしょうか?
    同システムの別箇所にてINSERT ... SELECT が実装されている箇所がありますので、バージョン的には利用可能です。
    INSERT ... SELECT に直せれば回避できるかもと判断された理由は、クエリ実行回数による制限やタイムアウト等、何らかの制限に引っ掛かったからなのではないかと考えられたということでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.09%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる