NHibernate通过独特的约束来插入线程插入

时间:2012-06-06 07:29:13

标签: c# multithreading nhibernate concurrency

我有一个多线程应用程序,它可以对同一类型的对象进行一些并发插入,这些对象具有标记为唯一的属性。

public class Foo(){
...
    string PropertyThatshouldBeUnique {get;set;}
...
}

每个线程都有自己的会话,并执行:

Foo myFooInstance = new Foo();
myFooInstance.PropertyThatshouldBeUnique = "Bar";
myThreadSession.SaveOrUpadte(myFooInstance);
  • 我的数据库表上有一个唯一的约束来阻止 多次插入,因此我在第二次插入时出现异常 插入,触发整个事务的回滚(这不好)
  • Concurrents插入可以非常接近(几毫秒)
  • 我没有配置任何特定的Nhibernate Concurrency strategy(不确定这是否可以解决我的问题或使用哪个)

我的问题是:

我应该如何以及在何处检查以前插入的具有相同属性值的Foo对象?

2 个答案:

答案 0 :(得分:0)

你可以在NHibernate中做这样的事情,而不是破坏你当前的架构吗?

if(!Update(connection))
{
    using (var command = new SqlCommand(@"INSERT INTO foo VALUES (Bar, ...)", connection))
    {
        try
        {   
            command.ExecuteNonQuery(); 
        }               
        catch (BlahUniqueConstraintException) // dummy exception, please replace with relevant
        {
            // very rarely will get in here
            Update(connection);
        }           
    }
}           

private bool Update(SqlConnection connection)
{
    // use update to do two things at once: find out if the record exists and also ... update
    using (var command = new SqlCommand(@"UPDATE foo SET ... WHERE PropertyThatshouldBeUnique = 'Bar'", connection))
    {
        // if the record exists and is updated then returns 1, otherwise 0
        return command.ExecuteNonQuery() > 0;
    }   
}

答案 1 :(得分:0)

这是很久以前发布的,但是当我发现自己处于同样的情况时,让我告诉你我找到了什么解决方案。

对于数据库操作,不是让每个线程通过Nhibernate完成工作,而是将它们的请求发送到另一个执行某种服务工作的线程。它暴露了一些像Insert这样的方法。

线程1想要插入Object1

线程2想要插入Object1

他们正在同时执行类似Thread3.Insert(Object1)的操作。

第一个调用Thread3收到,它打开一个会话到DB(无成本),它检查Object1不在DB中SELECT,然后添加它。

第二个调用Thread3收到,即使它在一个纳秒之后,它会执行相同但在SELECT之后停止并且不执行任何操作或发回异常。

等待处理第一个调用的成本非常低,毕竟您需要检查的数据库约束限制多线程速度(因此数据库访问)

就像说,嗯,我有2台非常快的PC和1台低服务器。

我认为它更像是一个设计问题,而不是Nhibernate功能。

线程之间的同步已经很复杂了,但是在使用UnitOfWork模式的线程之间同步数据库是一件痛苦的事。

(这是你的问题之一,因为你每次插入时都不会提交你的交易)

也许这里的一些大师有更好的想法。