6

因此,首先让我说明我要完成的工作。我有一个填充了工作的表。还有一个 Web 服务,其方法允许更改作业数据,称为SaveJob. 此方法检索作业及其所有数据,对新数据运行验证(需要对其他表进行一些数据库查询),然后将其保存回数据库。它有点慢。大约一秒钟。

偶尔会发生的情况是,两个SaveJob电话会在同一个工作上紧密联系在一起,它们会相互重叠。现在这是唯一的网络服务器,但我希望我的解决方案网络场兼容,所以即使我知道如何使用单例解决这个问题,我更愿意让数据库处理锁。

问题是当它尝试读取已被另一个 SaveJob 调用更改的作业时,我可以使用 NHibernate 和 SQL Server 数据库锁来阻止第二个 SaveJob 调用吗?

我相信答案是肯定的,但我不确定如何去做。我已经阅读了有关的文档,ISession.Lock()并且我相信我需要的是使用NHibernate.LockMode.Upgrade

我的下一个问题是这个锁什么时候释放?

我假设它在事务提交时被释放,但我找不到任何明确说明这一点的文档。

但是,如果是这种情况,那么有没有办法让我打开另一个事务并运行一些查询,而无需关闭我一开始就开始工作时开始的事务?还是我必须在一笔交易中完成这一切?

4

2 回答 2

11

首先,我建议不要跨多个线程使用单个事务,因为 ISession 本身不是线程安全的。

当您使用LockMode.Upgradeon 会话或 on 时session.Get(),NHibernate 将在您检索实体时发出一条select with (rowlock)语句(详细信息可能取决于数据库类型和配置)。如果对象先前被另一个线程检索过,则当前线程将等待直到锁被释放或超时到期。当update语句在 上执行时,锁本身是释放的transaction.Commit()。UsingLockMode.UpgradeNoWait提供了类似的功能,只是它不等待并且在获得锁定时简单地失败。

这篇Ayende 的帖子也有一些关于 SQL NHibernate 发出的信息session.Lock()

您可以在NHibernate 文档第 11 章第 6 节中阅读不同类型的锁。

于 2013-08-21T16:24:25.833 回答
3

偶尔会发生两个 SaveJob 调用会靠近在一起......

这些作业指向同一个数据库行还是它们是完全不同的实体?

如果它们指向一个作业实例,您可以使用乐观锁定version来禁止数据重写。

如果它们不同,那么它只是允许并发查询执行的数据库点。somehow slow可以是关于表/索引/标识符锁定。

不迟于提交后释放锁,取决于隔离级别。一些(读)锁在查询执行后立即释放,特定行内的更新可以在提交后释放。

编辑:

显然乐观锁对你不好,你需要使用

// 使用 SELECT ... FOR UPDATE 进行版本检查,然后重新关联:sess.Lock(pk, LockMode.Upgrade);

http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-update-lock

于 2013-08-21T16:22:32.640 回答