NHibernate中的工作单元和每个请求的会话

时间:2012-11-02 14:42:26

标签: c# nhibernate unit-of-work session-per-request

我想我的架构设置可能会导致我的工作单元设置错误。这是我目前所拥有的(缩进显示顺序):

HttpRequest.Begin()
  UnitOfWork.Begin()
    Session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);

在这里,我使用NHibernate调用各种服务来执行crud。当我想对数据库进行更改(更新/保存)时,我调用此代码:

        using (var transaction = unitOfWork.Session.BeginTransaction())
        {
            try
            {
                // These are just generics
                ret = (Key)unitOfWork.Session.Save(entity);
                transaction.Commit();
                rb.unitOfWork.Session.Clear();
            }
            catch
            {
                transaction.Rollback();
                rb.unitOfWork.Session.Clear();
                rb.unitOfWork.DiscardSession();
                throw;
            }
        }

当HttpRequest结束时,我执行以下步骤:

      UnitOfWork.Commit()
    Transaction.Commit() // This is my sessions transaction from the begin above

我遇到了能够回滚大批量流程的问题。因为我在我的CRUD层中提交我的事务,如上所示,我的事务不再处于活动状态,当我尝试在UnitOfWork中回滚时,由于事务已经提交,它什么都不做。我在我的CRUD层中提交代码的原因是我可以尽可能快地保留我的数据,而不会长时间锁定数据库。

采取上述情况的最佳行动方案是什么?我是否只进行了不提交批处理作业的特殊CRUD操作,只是在我的工作结束时处理提交,或者我的逻辑是否与我的UnitOfWork和Session Per Request有关?有什么建议吗?

1 个答案:

答案 0 :(得分:8)

您已经发现了每个请求会话模式如此受欢迎的原因以及可能源于对您的工作单元进行微观管理的问题。

通常,对于每个Web请求,在该请求中需要完成的所有操作都可以被视为一个工作单元,因此您可以在该单个Web中只打开一个工作单元和一个NHibernate会话请求。

另外,我认为你可能会因为你的问题中的这句话对NHibernate的工作方式感到有些困惑:“我在CRUD层提交代码的原因是我可以尽快保存我的数据而不用锁定数据库的时间太长了。“

NHibernate不会导致数据库中的任何锁定。每次调用ISession.Save(实体)时,只要不调用ISession.Flush()或ITransaction.Commit(),就不会将任何内容写入数据库,而是将其添加到要插入的项目队列或在Web请求结束时提交当前事务时在数据库中更新。

因此,每个请求的会话应如此设置:

void Application_BeginRequest()
{
    // Start your unit of work, open a session and begin a transaction
}

// Do all of your work ( Read, insert, update, delete )

void Application_EndRequest()
{
    try
    {
        // UnitOfWork.Current.Transaction.Commit();
    }
    catch( Exception e )
    {
        // UnitOfWork.Current.Transaction.Rollback();
    }
}

当然,有很多方法可以做同样的事情,但这是每个请求模式的会话基础 - 只有一个会话用于整个Web请求。