c# - NHibernate 锁定数据库表以避免插入 "duplicates"

标签 c# multithreading nhibernate locking

我认为这是一个常见问题,但我还没有找到任何解决方案,也许我没有在谷歌中正确搜索问题。总而言之,我有一个在表中插入多行的过程(在同一事务中的许多其他事物中),但该过程是在多个线程和多个服务器中执行的。

TABLE: COVERAGES
COLUMNS: COV_Id, COV_Description

描述是唯一的,但不是数据库中的约束(旧版),我想避免插入重复的描述。我已经将搜索和插入隔离在一个独立的事务中,我想在选择之前锁定表并在“保存”之后释放它(如果它不存在)。

我想要那样的东西(高级):

{
    this.Lock(Coverage); // Lock table Coverages to avoid select out of this transaction
    Coverage coverage = session.QueryOver<Coverage>().Where(g => g.Description == description).Take(1).SingleOrDefault();
    if (coverage == null)
    {
        this.Save(new Coverage { Description = description });
    }
    return coverage;
};

我不能使用C#的lock指令,因为进程是在多个服务器上执行的,我不能使用NHibernate的Lock指令,因为我恰恰想在没有结果的时候阻塞。

我正在为 SqlServer 和 Oracle 使用 NHibernate 3.3。

最佳答案

我终于在数据库上实现了一个信号量来解决这个问题。正如我在上面与 Frédéric 的“讨论”中提到的,我需要在选择时锁定线程以避免重复插入,Serializable 隔离级别,锁定 INSERT 并在 SQL Server 上的并发调用中调用插入时抛出死锁异常。通过其他方式,在 Oracle 上会抛出错误 08177。00000 -“无法序列化对此事务的访问”,或者一直等待另一个事务的结束插入稍后复制的值(请参阅下面的示例 sql)。

所以解决方案是这样的:

public Coverage CreateCoverageSessionIsolated(string description, out bool isNew)
{
    Coverage coverage = null;
    bool _isNew = false;
    this.ExecuteOnNewSession((session) =>
    {
        this.semphoresDao.LockSemaphore(session, "SMF_COVERAGES");
        coverage = session.QueryOver<Coverage>()
            .Where(g => g.Description == description)
            .Take(1) 
            .SingleOrDefault();
        _isNew = coverage == null;
        if (coverage == null)
        {
            coverage = new Coverage { Description = description };
            this.Save(coverage);
        }
    });
    isNew = _isNew;
    return coverage;
}

我对实际代码进行了一些调整以更好地理解。

  • ExecuteOnNewSession,启动一个新的隔离的 ReadCommitted 事务。因此它不会干扰已打开的事务,避免非受控锁超时和死锁并减少风险时间。
  • LockSempahore:执行选择查询,锁定特定行。

我已经尝试过了,在 SQL Server 和 Oracle 上运行良好。

编辑: 为了检查可序列化事务的解决方案是否适合我,我在两个并发事务上使用了那个简单的 SQL 代码,并排执行:

BEGIN TRAN; -- ONLY FOR SQL
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT COV_ID FROM COVERAGES WHERE COV_DESCRIPTION = 'testcov';
INSERT INTO COVERAGES (COV_DESCRIPTION) VALUES ('testcov');
COMMIT;

关于c# - NHibernate 锁定数据库表以避免插入 "duplicates",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43683920/

相关文章:

java - 如果我不是,谁在调用 Java 线程的 interrupt() 方法?

nhibernate - 对 id 属性使用自定义类型

c# - 覆盖/隐藏显式实现的接口(interface)方法

c# - 如何从 Asp.Net Core 应用程序将日志写入 Azure 应用程序 Insights?

c# - 如何将 native 窗口处理程序 (HWND) 嵌入到 C# WPF 应用程序中

NHibernate 3 - 状态如何?

nhibernate - 抽象 NHibernate 标准是否有值(value)?

c# - 对于引用类型,使用 IEquatable<T> 如何减少强制转换的使用?

multithreading - @Async 与 Spring 中的 Reactor 线程池

找不到错误C