微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

asp.net – 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解决了问题,但我不是数据库专家.这是解决问题的适当方法,还是应该如何调整逻辑?

解决方法

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

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

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

>创建一个包含列的序列表(我猜)MallID,nextVoucher,maxVouchers
>使用mallid,1表示该表,以及每个商场的限制
>将插入逻辑更改为此伪代码

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是我:-)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐