0

ユーザー テーブル構造 ID ユーザー名 (一意の制約)

このようなNhibernateとSqlServerに問題があります。ユーザー テーブルにデータを挿入しようとしている 2 つの同時トランザクションがあります。どちらのトランザクションも、テーブル内のデータをクエリして、挿入する新しいユーザー名がテーブルに表示されないかどうかを確認します。問題はそれを言うことです。トランザクション 1 とトランザクション 2 はユーザー テーブルを読み取り、ユーザー テーブルにユーザー名 embarus がないことを発見しました。次に、Transaction2 がユーザー テーブルに embarus を挿入しようとしていますが、Transaction1 はすでにテーブルに embarus を挿入してコミットしています。

したがって、トランザクション 2 は一意の制約の例外を取得します。

この問題を解決するのを手伝ってください。役立つアイデアや記事があれば教えてください。

SqlServer 2008 では、デフォルトのトランザクション分離レベルに ReadCommitted が使用されていることがわかりました。

どうもありがとう。

4

1 に答える 1

1

一意の制約違反をキャッチして処理する必要があります。これを行う最善の方法は、ISqlExceptionConverter 実装を作成して、RDBMS 固有の例外をアプリケーションのカスタム例外に変換することです。

public class SqlServerExceptionConverter : ISQLExceptionConverter
{
    public Exception Convert(AdoExceptionContextInfo adoExceptionContextInfo)
    {
        var sqlException = adoExceptionContextInfo.SqlException as SqlException;
        if (sqlException != null)
        {
            // 2601 is unique key, 2627 is unique index; same thing: 
            // http://blog.sqlauthority.com/2007/04/26/sql-server-difference-between-unique-index-vs-unique-constraint/
            if (sqlException.Number == 2601 || sqlException.Number == 2627)
            {
                return new UniqueKeyException(sqlException.Message, sqlException);
            }
        }
        return adoExceptionContextInfo.SqlException;
    }
}

public class UniqueKeyException : Exception
{
    public UniqueKeyException(string message, Exception innerException)
        : base(message, innerException)
    { }
}

使用法:

            using (var txn = _session.BeginTransaction())
            {
                try
                {
                    var user= new User
                        {
                            Name = "embarus"
                        };
                    _session.Save(user);
                    txn.Commit();
                }
                catch (UniqueKeyException)
                {
                    txn.Rollback();
                    var msg = string.Format("A user named '{0}' already exists, please enter a different name or cancel.", "embarus");
                    // Do something useful
                }
                catch (Exception ex)
                {
                    if (txn.IsActive)
                    {
                        txn.Rollback();
                    }
                    throw;
                }
            }

例外が発生した後は、セッションを再利用しないでください。

于 2013-04-16T12:33:08.493 に答える