Nhibernate,多线程和竞争条件

时间:2009-11-23 20:03:01

标签: multithreading nhibernate race-condition

使用NHibernate以异步方式保存到数据库时遇到竞争问题。首先,异步完成对数据库的插入,其中自动生成唯一ID。在此插入之前返回主线程,现在持久化对象具有唯一的数据库生成id,该对象以某种方式更新。如果我调用session.Update,更新将失败,因为要更新的对象尚未具有id值。如果我调用SaveOrUpdate,它显然会导致插入而不是Update,因为我的实体的id字段等于unsaved-value属性。希望这段代码能够使情况更加清晰:

Entity entity = new Entity()
//update some fields
entity.PropertyTwo = "new value";
//dataObject as the database auto-generated Id
//insert new row asynchronously in different thread
Entity entity.Id = dao.save(entity.Clone()).Id

//before the the entity is returned from the database, the entity might be updated
entity.Property = 'new value';
//entity might be sent without an Id since the first asynch call has not returned yet.
//update asynchronously in another thread
Object dataObject = dao.Update(entity); //fails because Id is not set yet

一种解决方案是在保存之前在代码中生成唯一ID。在这种情况下,应用程序管理唯一ID的递增而不是数据库。还有其他任何处理方法吗?

2 个答案:

答案 0 :(得分:1)

看起来你可以在一个NHibernate Session中创建多个线程。 NHibernate中的会话不是线程安全的。您永远不应该在两个并发线程中访问同一个Session。尝试在新线程中创建一个单独的会话,看看它是否能解决您的问题。

查看NHibernate documentation section 10.2

答案 1 :(得分:0)

在调用update之前,需要设置某种“等待插入完成”类型逻辑。这是标准的多线程异步编程。

可以在多线程环境中的同一对象上同时调用Insert和Update。您只需要确保底层代码足够智能:

  1. 在更新前执行插入
  2. 在开始更新之前等待插入完成
  3. 有很多不同的方法可以做到这一点,但没有一种方法比另一方更好。从概念上讲,您需要一个可以获取,丢弃并等待的锁。

    此外,这个问题与NHibernate没有任何关系。多线程编程非常困难。最好避免多线程,因为复杂性很容易失控。