NHibernate - 悲观锁定无法正常工作

时间:2010-11-23 08:22:52

标签: nhibernate concurrency pessimistic-locking

跟进this other question

我正在尝试为并发问题实现悲观锁定,正如我在上面的问题中所描述的那样(请随意添加到那个)。但它不适合我。

我做了一个非常简单的测试:我有两个单独的站点运行,这两个站点都增加了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 的值,因此大约一半的更新因并发而丢失。我究竟做错了什么?我在此测试中禁用了二级缓存。我使用错误的锁定模式吗?我应该指定一个isoliation级别吗?还要别的吗?提前谢谢。

编辑: FluentNhibernate配置:

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"));

1 个答案:

答案 0 :(得分:0)

要使LockMode.Upgrade生效,所有交易都必须包含在交易中,因为LockMode.Upgrade所做的就是将其锁定到当前交易中。

您的问题很可能是由于这些陈述没有包含在交易中。

乐观锁定不适用于单个语句,而是适用于彼此分离的多个事务。一个例子:

  1. 开始交易;

  2. Id = 42;

  3. 获取记录
  4. 结束交易。

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

    之后:

    1. 开始交易;

    2. Id = 42;

    3. 获取记录
    4. 检查计数器是否与第一笔交易中收到的值保持不变;

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

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

    5. 结束交易。

    6. 乐观锁定意味着您“希望”Counter在两个事务之间没有发生变化,并处理它已发生变化的情况。使用悲观锁定,您可以确保在单个事务中完成所有更改,并锁定所有必需记录。

      B.t.w。:检查机制(Counter是否在平均时间内发生了变化)可以由NHibernate自动处理。