nhibernate僵局

时间:2009-08-04 20:03:29

标签: asp.net sql-server nhibernate

我在ASP.NET页面中使用以下代码来创建记录,然后计算记录以确保我没有超过设置限制并回滚事务(如果有的话)。

using (var session = NhibernateHelper.OpenSession())
using (var transaction = session.BeginTransaction())
{
    session.Lock(mall, LockMode.None);

    var voucher = new Voucher();
    voucher.FirstName = firstName ?? string.Empty;
    voucher.LastName = lastName ?? string.Empty;
    voucher.Address = address ?? string.Empty;
    voucher.Address2 = address2 ?? string.Empty;
    voucher.City = city ?? string.Empty;
    voucher.State = state ?? string.Empty;
    voucher.Zip = zip ?? string.Empty;
    voucher.Email = email ?? string.Empty;
    voucher.Mall = mall;
    session.Save(voucher);

    var issued = session.CreateCriteria<Voucher>()
        .Add(Restrictions.Eq("Mall", mall))
        .SetProjection(Projections.Count("ID"))
        .UniqueResult<int>();

    if (issued >= mall.TotalVouchers)
    {
        transaction.Rollback();
        throw new VoucherLimitException();
    }

    transaction.Commit();
    return voucher;
}        

但是,我遇到了很多僵局。我认为发生这种情况是因为我正在尝试计算表中的记录,我刚刚执行了插入操作,并且锁仍然保留在插入的行上,从而导致死锁。

  • 有人能证实吗?
  • 有人可以建议修复吗?

我尝试在最终查询中调用SetLockMode(LockMode.None),但这会导致我无法理解的NullReferenceException。

编辑:如果我在保存对象之前运行查询,它可以工作,但是我没有完成验证我的插入没有以某种方式超过限制(在并发插入的情况下)的目标。

编辑:我发现在session.BeginTransaction调用中使用IsolationLevel.ReadUncommited解决了这个问题,但我不是数据库专家。这是问题的合适解决方案还是我应该如何调整逻辑?

2 个答案:

答案 0 :(得分:3)

该设计将容易出现死锁 - 通常(并非总是)一个连接不太可能自行死锁,但是针对同一个表执行插入和聚合的多个连接很可能会死锁。这是因为虽然一个事务中的所有活动从执行工作的连接的角度看都是完整的 - 但数据库不会将事务锁定在“自己的”记录之外 - 来自OTHER事务的聚合查询将尝试锁定整个桌子或它的大部分同时,那些会陷入僵局。

在这种情况下,

读取未提交是你的朋友,因为它基本上说“忽略锁定”,这在某种程度上意味着违反了你围绕数据设置的规则。 I.E.表中记录的计数将是不准确的,您将对该不准确的计数采取行动。当真正的答案是11时,你的计数将返回10或13。

我最好的建议是重新排列插入逻辑,以便捕获计数的概念,而无需计算行数。你可以去几个方向。我有一个想法是这样:用插入的凭证对序列进行编号,并对序列本身施加限制。

  1. 制作一个包含列的序列表(我猜)MallID,nextVoucher,maxVouchers
  2. 使用mallids,1表示该表,并为每个商场设置限制
  3. 将插入逻辑更改为此伪代码:
  4. Begin Transaction
    Sanity check the nextVoucher for Mall in the sequence table; if too many exist abort
    If less than MaxVouchers for Mall then {
      check, fetch, lock and increment nextVoucher
      if increment was successful then use the value of nextVoucher to perform your insert. 
        Include it in the target table.
    }
    Error? Rollback
    No Error? Commit
    

    这样的序列表会损害并发性,但我认为并不像计算表中的行那样频繁。一定要进行性能测试。 此外,[检查,获取,锁定和增量]很重要 - 您必须排除序列表中的行,以防止某些其他连接在递增之前在分秒中使用相同的值。我知道这个的SQL语法,但我担心我不是nHibernate专家。

    对于读取未提交的数据错误,请查看:http://sqlblog.com/blogs/merrill_aldrich/archive/2009/07/29/transaction-isolation-dirty-reads-deadlocks-demo.aspx(免责声明:Merrill Aldrich是我: - )

答案 1 :(得分:0)

2个问题:

  1. 优惠券被删除的频率
  2. 任何异议(超出纯度)到a     db level trigger?