2009-11-23 62 views
0

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

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。在这种情况下,应用程序管理唯一标识的增量,而不是数据库。任何其他方式处理这个?

回答

1

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

查看NHibernate documentation section 10.2

+0

不,我正在为每个线程创建一个会话。如果在插入完成之前在实体上更新更新 – infinity 2009-11-24 18:56:17

+0

记住每个数据库调用都发生在另一个线程上,所以如果在第二个线程上尝试更新,然后插入在前一个线程上完成,则会出现竞态条件错误。 – infinity 2009-11-24 19:02:12

+0

你能解释为什么你要克隆实体对象并保存克隆?你可能已经试过了,但是如果你在同一个实体对象(无克隆)的所有线程中执行SaveOrUpdate(),那么无论哪个线程首先插入,其他线程都会执行更新。这是否适合您的设计? – 2009-11-24 21:52:01

0

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

在多线程环境中,很可能在同一个对象上同时调用Insert和Update。你只需要确保底层代码是足够聪明到:

  1. 执行插入更新之前
  2. 等待插入到开始更新之前,

有许多不同的方式完成要做到这一点,他们都不一定比另一个更好。你在概念上需要一个锁,你可以获取,放弃和等待。

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