NHibernate - 悲观锁不工作 [英] NHibernate - pessimistic locking not working

查看:160
本文介绍了NHibernate - 悲观锁不工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此其他问题的后续跟进。 p>

我试图为并发问题实现悲观锁定,正如我在上面的问题中所描述的(请随便添加一个)。但它不为我工作。



我做了一个非常简单的测试:我有两个独立的网站运行,都增加一个计数器500倍。我同时运行它们。最后,我希望我表中的某一列有一个值1000。



这里是代码。当然,它不是生产代码,但是测试代码还是不行,它应该仍然工作,对吗?

  for(int i = 0 ; i <500; i ++)
{
var tx = this.userRepo.Session.BeginTransaction();
var user = this.userRepo.GetById(42);
user.Counter ++;
userRepo.Save(user);
tx.Commit();
}

GetById 方法使用LockMode.Upgrade:

  public T GetById(int id)
{
T obj = Session。 Get< T>(id,LockMode.Upgrade);
return obj;
}



现在,使用NHProfiler我看到下面的SQL语句:



SELECT ID FROM'User'WHERE Id = 42 for update



但结果是大约 530 的值,因此大约有一半的更新由于并发而丢失。我做错了什么?我在这个测试中禁用了二级缓存。我使用错误的锁定模式?我应该指定隔离级别吗?还要别的吗?提前感谢。



EDIT: FluentNhibernate配置:

 code> Fluently.Configure()
。数据库(MySQLConfiguration.Standard.ConnectionString(connectionstring))
.Mappings(m => assemblyTypes.Select(t => t.Assembly)。 ToList()。ForEach(a => m.FluentMappings.AddFromAssembly(a)))
.ExposeConfiguration(c => c.Properties.Add(hbm2ddl.keywords,none))

解决方案

LockMode.Upgrade 工作,所有事务必须包含在一个事务中,因为 LockMode.Upgrade 会将其锁定到当前事务中。



您的问题很可能是由于这些语句未包含在事务中。



乐观锁定不适用于单个语句,但对于彼此分离的多个事务。例如:


  1. 开始交易;


  2. 通过 Id = 42 ;


  3. 获取记录


然后,在交易之外,增加 Counter



之后:


  1. 开始交易

    b
  2. 通过 Id = 42 ;

    获取记录

  3. 检查计数器是否已经与第一次交易中收到的价值不变;



    a。如果没有更改,请使用增加的值更新计数器;



    b。如果已更改,请处理已更改的值。


  4. 结束事务。


乐观锁定意味着希望计数器在两个事务之间没有更改,并处理它已更改的情况。使用悲观锁定,您可以确保所有更改都在单个事务中完成,并锁定所有必需的记录。



Btw:检查机制( 在平均时间已更改)可以由NHibernate自动处理。


Follow up of this other question.

I'm trying to implement pessimistic locking for a concurrency issue as I described in the question above (please, feel free to add to that one). But it's not working for me.

I do a very simple test: I have two seperate sites running that both increase a counter 500 times. I run them simultaneously. In the end, I expect that a certain column in my table has, you guess it, a value of 1000.

Here is the code. It's no production code of course, but test code or not, it should still work, right?

for (int i = 0; i < 500; i++)
{
  var tx = this.userRepo.Session.BeginTransaction();
  var user = this.userRepo.GetById(42);
  user.Counter++;
  userRepo.Save(user);
  tx.Commit();
}

The GetById method uses LockMode.Upgrade:

public T GetById(int id)
{
  T obj = Session.Get<T>(id, LockMode.Upgrade);
  return obj;
}

Now, using NHProfiler I see the following SQL statement:

SELECT Id FROM 'User' WHERE Id = 42 for update

but the result is a value of around 530, so that's about half of the updates lost due to concurrency. What am I doing wrong? I disabled second level cache in this test. Am I using the wrong lock mode? Should I specify an isoliation level? Anything else? Thanks in advance.

EDIT: FluentNhibernate config:

Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString(connectionstring))
.Mappings(m => assemblyTypes.Select(t => t.Assembly).ToList().ForEach(a => m.FluentMappings.AddFromAssembly(a)))
.ExposeConfiguration(c => c.Properties.Add("hbm2ddl.keywords", "none"));

解决方案

For the LockMode.Upgrade to work, all transactions have to be enclosed in a transaction because what LockMode.Upgrade does is lock it into the current transaction.

Your problem will most likely be due to the statements not being enclosed in a transaction.

Optimistic locking does not apply to a single statement, but to multiple transactions that are separated from each other. An example:

  1. Begin a transaction;

  2. Get record by Id = 42;

  3. End the transaction.

Then, outside of the transaction, increase Counter.

After that:

  1. Begin a transaction;

  2. Get record by Id = 42;

  3. Check whether counter has been unchanged from the value received in the first transaction;

    a. If it hasn't changed, update the counter with the increased value;

    b. If it has changed, handle the changed value.

  4. End the transaction.

Optimistic locking means that you "hope" the Counter hasn't changed between the two transactions and handle the case where it has changed. With pessimistic locking, you ensure that all changes are done within a single transaction with all required records locked.

B.t.w.: the checking mechanism (whether Counter has changed in the mean time) can be automatically handled by NHibernate.

这篇关于NHibernate - 悲观锁不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆