Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
NHibernate:独占锁定_Nhibernate_Locking - Fatal编程技术网

NHibernate:独占锁定

NHibernate:独占锁定,nhibernate,locking,Nhibernate,Locking,在NHibernate中,我希望检索一个实例,并在表示数据库中检索到的实体的记录上放置一个独占锁 现在,我有以下代码: With.Transaction (session, IsolationLevel.Serializable, delegate { ICriteria crit = session.CreateCriteria (typeof (TarificationProfile)); crit.SetLockMode (LockMode.Upgrade);

在NHibernate中,我希望检索一个实例,并在表示数据库中检索到的实体的记录上放置一个独占锁

现在,我有以下代码:

With.Transaction (session, IsolationLevel.Serializable, delegate
{
    ICriteria crit = session.CreateCriteria (typeof (TarificationProfile));

    crit.SetLockMode (LockMode.Upgrade);

    crit.Add (Expression.Eq ("Id", tarificationProfileId));

    TarificationProfile profile = crit.UniqueResult<TarificationProfile> ();

    nextNumber = profile.AttestCounter;

    profile.AttestCounter++;

    session.SaveOrUpdate (profile);
});
但是,我希望能够使用真正的独占锁。也就是说,在我释放锁之前,防止其他人读取相同的记录。 换句话说,我希望能够使用
xlock
锁定提示,而不是
updlock

我不知道如何(甚至是否)实现这一目标。。。。也许有人能给我一些提示:)


如果确实有必要,我可以使用NHibernate的SQLQuery功能,编写我自己的SQL查询,但是,我希望尽可能避免这种情况。

如果要确保在事务期间从数据库读取的值不会更改,可以使用隔离级别的“可重复读取”。但在所有关键事务中都必须这样做。或者使用升级锁将其锁定在关键读取事务中。

如果所有读取操作都是使用IsolationLevel的Serializable完成的,而所有写入操作也都是使用IsolationLevel的Serializable完成的,我不明白为什么需要自己锁定数据库行

所以序列化可以保证数据的安全,现在我们仍然有可能出现死锁的问题

如果死锁并不常见,那么在出现死锁时,将[start transaction,read,update,save]放入重试循环就足够了

否则,可以使用直接生成的简单“select for update”语句(例如,不使用nhibernate)在更改行之前停止另一个事务读取该行


然而,我一直在想,如果更新速度快到足以导致大量死锁,ORM可能不是更新的正确工具,或者数据库模式可能需要重新设计,以避免必须读/写的值(例如,在读取数据时计算它)

我怀疑从NHibernate可以做到这一点。就我个人而言,我会使用存储过程来完成您试图完成的任务

更新:鉴于持续的反对票,我将对此进行详细介绍。Frederick在他的ORM层询问如何使用锁提示,锁提示是其底层数据库引擎的特定于语法和实现的细节。尝试执行这种操作的级别是错误的-即使可能(不是),它在所有NHibernate支持的数据库中一致工作的可能性也非常低


很好,Frederick的最终解决方案不需要先发制人的独占锁(这会降低性能,通常是个坏主意,除非您知道自己在做什么),但我的答案是正确的。任何偶然发现这个问题并想从NHibernate读取时执行独占锁定的人-第一:不要,第二:如果必须,使用存储过程或SQLQuery。

HQL DML查询将在不需要锁定的情况下完成更新

这在NHibernate 2.1中提供,但在参考文档中尚未提供。Java与NHibernate实现非常接近

假设您使用的是ReadCommitted隔离,那么您就可以安全地将值读回事务中

With.Transaction (session, IsolationLevel.Serializable, delegate
{
    session.CreateQuery( "update TarificationProfile t set t.AttestCounter = 1 + t.AttestCounter where t.id=:id" )
        .SetInt32("id", tarificationProfileId)
        .ExecuteUpdate();

    nextNumber = session.CreateQuery( "select AttestCounter from TarificationProfile where Id=:id" )
        .SetInt32("id", id )
        .UniqueResult<int>();
}

为什么要实现独占锁?可能还有其他的解决办法。为什么?因为这是必要的。。。我的实体包含一个应该使用的计数器,我必须绝对确保这个计数器使用正确…你不应该在阅读时锁定吗?是的,我想在阅读时锁定,但这是我不能做的,或者至少,NHibernate不能做的。我想让NHibernate发布一个选择。。从带有(xlock)语句的表中,但它不这样做。是的,它这样做。RDMBS是SQLServer2005SP3THX,对于您的回答,您能详细说明一下吗?我使用一个事务,在其中我读取实体(现在使用updlock),并将更新的实体保存在同一事务中。因此,该实体在该事务中不能更改。其他事务可以读取该值,并且可以在其事务期间看到您的更改。如果他们不喜欢这个,他们必须自己制作锁。或者使用“可重复读取”。即使使用Serializable,读取也只能取出共享锁。如果有多个类似的事务访问这个表(假设同一段代码同时在不同的线程上运行),这将导致死锁,因为两个线程都不能升级到独占锁来执行write.Nice,但我还需要知道下一个计数器。因此,我需要检索新值…@Frederik更新了示例以获取新值您确定会得到正确的计数器吗?我的意思是,这里是否没有等待发生的竞速条件,或者它是通过可序列化隔离级别解决的?关于这个主题有什么结论吗?我很想知道这种方法是否有效。(如果它真的有效,你应该接受答案)Frederik:你甚至不需要serializable-readcommitted就可以了,因为你在读tx之前就写了。
With.Transaction (session, IsolationLevel.Serializable, delegate
{
    session.CreateQuery( "update TarificationProfile t set t.AttestCounter = 1 + t.AttestCounter where t.id=:id" )
        .SetInt32("id", tarificationProfileId)
        .ExecuteUpdate();

    nextNumber = session.CreateQuery( "select AttestCounter from TarificationProfile where Id=:id" )
        .SetInt32("id", id )
        .UniqueResult<int>();
}
update TarificationProfile
set    AttestCounter = 1 + AttestCounter
where  Id = 1 /* @p0 */

select tarificati0_.AttestCounter as col_0_0_
from   TarificationProfile tarificati0_
where  tarificati0_.Id = 1 /* @p0 */