web-dev-qa-db-ja.com

「SqlConnectionは並列トランザクションをサポートしません」はいつ発生しますか?

私は何ヶ月もここにあるかなり動作するコードをたくさん持っていますが、今日は次の例外が記録されました:

_System.InvalidOperationException
SqlConnection does not support parallel transactions.
    at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(
       IsolationLevel iso, String transactionName)
    at System.Data.SqlClient.SqlConnection.BeginTransaction(
       IsolationLevel iso, String transactionName)
    at my code here
_

この例外がスローされた理由を調査したいと思います。私はBeginTransaction()のMSDNの説明を読みましたが、それが言っているのは、この例外がスローされることがあるということだけです。

この例外はどういう意味ですか?私が探しているコードの欠陥は何ですか?

25
sharptooth

接続にコミットされていないトランザクションが既にあり、BeginTransactionを再度呼び出すと、これを取得します。

この例では:

class Program
{
    static void Main(string[] args)
    {
        using (SqlConnection conn = new SqlConnection("Server=.;Database=TestDb;Trusted_Connection=True;"))
        {
            conn.Open();

            using (var tran = conn.BeginTransaction())
            {
                using (var cmd = new SqlCommand("INSERT INTO TESTTABLE (test) values ('" + DateTime.Now.ToString() + "')", conn))
                {
                    cmd.Transaction = tran;
                    cmd.ExecuteNonQuery();
                }

                using (var tran2 = conn.BeginTransaction())    // <-- EXCEPTION HERE
                {
                    using (var cmd = new SqlCommand("INSERT INTO TESTTABLE (test) values ('INSIDE" + DateTime.Now.ToString() + "')", conn))
                    {
                        cmd.Transaction = tran2;
                        cmd.ExecuteNonQuery();
                    }

                    tran2.Commit();
                }

                tran.Commit();
            }
        }
    }
}

... 2回目のBeginTransactionでもまったく同じ例外が発生します。

最初のトランザクションが次のトランザクションの前にコミットまたはロールバックされていることを確認してください。

ネストされたトランザクションが必要な場合は、 TransactionScope が先の方法であることがわかります。

19
SimonGoldstone

トランザクションに「間違った」メソッドを使用すると、同じ問題が発生します。これは、Entity Frameworkの新しいバージョンにアップグレードした後に発生しました。

以前は、次のメソッドを使用してトランザクションを作成し、EF強い型付きlinqクエリとSqlクエリを混在させていましたが、Connectionプロパティが存在しなくなったため、すべてのdb. with db.Database、これは間違っていました:

// previous code
db.Connection.Open();
using (var transaction = db.Connection.BeginTransaction())
{
    // do stuff inside transaction
}
// changed to the following WRONG code
db.Database.Connection.Open();
using (var transaction = db.Database.Connection.BeginTransaction())
{
    // do stuff inside transaction
}

どこかで、新しいバージョンのEntity Frameworkでそのトランザクションメソッドの動作の動作を変更し、ソリューションを使用することです:

db.Database.Connection.Open();
using (var transaction = db.Database.BeginTransaction())
{
    // do stuff inside transaction
}

トランザクションはDatabaseではなくConnectionで呼び出されることに注意してください。

11
Silvermind