为什么NHibernate Session.Save会锁定数据库?

时间:2013-03-03 10:26:33

标签: sql-server nhibernate dotnetopenauth

我用NHibernate构建了一个小型ASP.NET MVC Web应用程序作为ORM。在每个HTTP请求开始时,我创建一个会话并打开一个事务并在请求结束时关闭它。

// Begin request

session = StaticSessionManager.OpenSession();    
session.BeginTransaction();

// End of request

currentSession.Transaction.Commit();
currentSession.Flush();
currentSession.Close();

现在我也在使用DotNetOpenAuth API进行Facebook / Google登录。为了让我注册一个新用户,API希望我用一些用户信息更新表(比如UserProfile)。我正在通过Nhibernate的Save()

来做
session.Save(new UserProfile { UserName = userName });

在同一个Web请求中,DotNetOpenAuth API希望从该表中读取上面插入的数据(UserProfile)。

现在这导致死锁情况,因为NHibernate的Save在数据库上应用了某种锁定。即使我手动尝试使用SQL Server Management studio从该表读取数据,它似乎要等到Web请求超时。

现在我在Save

之后尝试了显式刷新
session.Flush();

但即使这样也没有摆脱锁定。我希望我的DotNetOpenAUth API能够读取最新的数据。

目前,我在保存后将交易记录下来,之后再重新开放。我不确定这是最佳做法/有任何缺点。

1 个答案:

答案 0 :(得分:4)

什么时候打电话给Flush?

使用默认设置(FlushMode上的ISession),在NHibernate事务上调用Commit()将自动刷新更改。在某些情况下,我们希望手动刷新,但在事务提交之后调用Flush()有很多原因:

  • 由于提交本身已经刷新,我们知道刷新没有更多更改,因此它没用。然而,NHibernate不知道它没用,所以它仍然会检查所有加载的对象。也就是说,超级氟化物冲洗对性能不利。

  • 如果确实有一些脏状态要发送到数据库,这样的更新将在事务之外执行,这通常不是我们想要的。

数据库锁定

通常,当数据库获取某种类型的锁时,该锁将一直保留,直到提交或回滚事务为止。刷新不会终止事务,因此对锁没有释放效果。

尝试解决方案

根据您的描述,您似乎使用一个数据库连接(通过NHibernate会话)来创建UserProfile,并使用另一个数据库连接(在同一个Web请求中)来读取它。后来的连接阻塞,因为第一个连接上的事务尚未完成。 (显然它必须锁定,因为数据库还不知道交易是否成功。)

尝试找到以下任何一种方法:

  • 创建用户配置文件时,请在返回前提交的单独事务(可能还有会话)上执行此操作。

  • 或者使用户配置文件的“回读”使用相同的数据库连接,以便可以在同一事务中完成。我不熟悉DotNetOpenAuth API,但看看是否有办法覆盖读取操作,因此您可以通过NHibernate完成,或者尝试将session.Connection注入DotNetOpenAuth。