0

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

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 的递增,而不是数据库。还有其他处理方法吗?

4

2 回答 2

1

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

查看NHibernate 文档第 10.2 节

于 2009-11-24T05:07:09.820 回答
0

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

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

  1. 在更新前进行插入
  2. 在开始更新之前等待插入完成

有许多不同的方法可以做到这一点,而且没有一种方法一定比另一种更好。从概念上讲,您需要一个可以获取、丢弃和等待的锁。

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

于 2009-11-27T11:37:33.647 回答