Nhibernate两个事务读取同一个表并插入同一个表会使一个事务失败
本文关键字:事务 同一个 失败 一个 两个 读取 Nhibernate 插入 | 更新日期: 2023-09-27 18:09:29
User表结构Id用户名(唯一约束)
我有Nhibernate和SqlServer这样的问题。有两个并发事务试图在User Table中插入数据。两个事务都查询表中的数据,以检查要插入的新Username是否没有出现在表中。问题是。Transaction1和Transaction2读取用户表,发现用户表中没有用户名embarus。当Transaction1已经在表中插入并提交了embarus时,Transaction2试图在User表中插入embarus。
因此,Transaction2得到唯一约束的异常。
请帮助我解决这个问题,任何可能有用的想法或文章。
我发现SqlServer 2008使用ReadCommitted作为默认事务隔离级别。
您需要捕获并处理唯一的约束违反。最好的方法是创建一个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;
}
}