2

我用 NHibernate 作为 ORM 构建了一个小型 ASP.NET MVC Web 应用程序。在每个 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 请求超时。

现在我在保存后尝试了显式刷新

session.Flush();

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

目前,我在保存后进行交易,然后再重新打开一次。我不确定这是否是最佳做法/有任何缺点。

4

1 回答 1

4

何时调用 Flush?

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

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

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

数据库锁定

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

尝试的解决方案

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

尝试找到一种方法来执行以下任何操作:

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

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

于 2013-03-03T14:29:31.517 回答