1
我有一个可以被多个程序访问的SQL Server数据库。这些程序用C#编写,并使用Fluent NHibernate作为ORM。但是数据库中存在一些对象(称为令牌),根据域逻辑,不应允许多个进程/线程同时处理它们。正确处理StaleObjectStateException
我试图通过NHIbernate版本锁定实现此目的。我有以下映射
mapping.OptimisticLock.Version();
mapping.Version(token => token.VersionTimestamp).Generated.Always().UnsavedValue(null).Access.Property().CustomSqlType("timestamp").Nullable();
和下面的代码:
var token = Session.Get<Token>(tokenId);
if (token.Status != TokenStatus.Available)
return new FailedResult("Token not available");
try
{
token.Status = TokenStatus.Locked;
Session.SaveOrUpdate(token);
}
catch (StaleObjectStateException)
{
WriteLogsToDb(); // <- another StaleObjectStateException thrown here
return new FailedResult("Could not acquire token");
}
ProcessToken(token); // do stuff that isn't allowed to be done concurrently by multiple threads/processes
token.Status = TokenStatus.Available;
Session.SaveOrUpdate(token);
return new SuccessResult();
的问题是,我得到一个StaleObjectStateException
后,我无法保存任何东西到DB(即使是没有版本的实体映射)。我得到另一个StaleObjectStateException
。但是我无法锁定令牌后,我真的需要在DB中写入日志和其他一些东西。
什么是正确的方法来做到这一点? NHibernate的这种行为的原因是什么?
可悲的是,加入'Session.Evict'或'Session.Refresh'没有效果。我忘记提到'Session.SaveOrUpdate'是一个覆盖,它在内部创建一个事务,调用NHibernate的'SaveOrUpdate',然后提交事务。 – holdenmcgrohen
请给我看看您正在调用WriteLogsToDb()的异常文本。和这种方法的代码。 –
在关于并发性的Ayende帖子中:http://ayende.com/blog/3946/nhibernate-mapping-concurrency 我发现这个: 如果更新因为行更新而失败,我们将得到一个StaleObjectException。与所有例外情况一样,这会使会话不符合使用条件,您将不得不创建新会话来处理它._ 因此,您必须创建一个新会话才能在此情况下写入日志。 –