加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net – nhibernate死锁

发布时间:2020-12-16 03:50:51 所属栏目:asp.Net 来源:网络整理
导读:我在ASP.NET页面中使用以下代码来创建记录,然后计算记录以确保我没有超过设置限制并回滚事务(如果有). using (var session = NhibernateHelper.OpenSession())using (var transaction = session.BeginTransaction()){ session.Lock(mall,LockMode.None); var
我在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是我:-)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读