我有一个可由多个程序访问的SQL Server数据库。程序使用Fluent NHibernate作为对象关系映射,用C#编写。但是,根据域逻辑,数据库中有一些对象(称为令牌)不应该允许由多个进程/线程等并发处理它们。
我试图通过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之后,我无法将任何其他内容保存到数据库中(即使是没有版本映射的实体)。我得到了另一个StaleObjectStateException。但在我无法锁定令牌后,我真的需要将日志和其他一些东西写入数据库中。
正确的做法是什么?NHibernate这种行为的原因是什么?
发布于 2015-04-19 21:49:38
会话是UoW,它在刷新操作期间合并您所做的所有更改并接受它。因为你在刷新过程中得到了一个异常(不带事务的SaveOrUpdate执行刷新),你的对象(令牌)仍然被标记为脏的,并且在下一次刷新时尝试保存它,如果它仍然被锁定,你会再次得到一个异常。
要避免这种情况,您必须在保存任何其他内容之前从会话中删除对象:
try
{
token.Status = TokenStatus.Locked;
Session.SaveOrUpdate(token);
}
catch (StaleObjectStateException)
{
Session.Evict(token); // <- remove token from session
WriteLogsToDb(); // <- another StaleObjectStateException thrown here
return new FailedResult("Could not acquire token");
} https://stackoverflow.com/questions/29698473
复制相似问题