1

我读过很多帖子说多线程应用程序必须为每个线程使用单独的会话。也许我不明白锁定是如何工作的,但是如果我在所有存储库方法中锁定会话,那不会使单个静态会话线程安全吗?

像:

public void SaveOrUpdate(T instance)
{
    if (instance == null) return;
    lock (_session)
        using (ITransaction transaction = _session.BeginTransaction())
        {
            lock (instance)
            {
                _session.SaveOrUpdate(instance);
                transaction.Commit();
            }
        }
}

编辑:

请考虑我正在编写的应用程序的上下文/类型:

不是多用户,也不是典型的用户交互,而是一个自动运行的机器人,它可以对财务数据和订单更新等远程事件做出反应,并据此执行任务和保存。间歇性地,这可以创建每秒最多 10 次保存的集群。通常,每次都需要保存同一个对象图。此外,在启动时,程序确实将完整的数据库加载到实体对象图中。所以它基本上只读取一次,然后在运行时执行 SaveOrUpdates。

4

2 回答 2

4

鉴于应用程序通常正在编辑相同的对象图,也许有一个线程专门用于将这些编辑应用于对象图然后将它们保存到数据库中,或者可能是一个线程池服务于一个公共队列编辑,其中每个线程都有它自己的(专用)会话,它不需要锁定。查找生产者/消费者队列(开始,看这里)。

像这样的东西:

[Producer Threads]
Edit Event -\                [Database Servicer Thread]
Edit Event ------> Queue -> Dequeue and Apply to Session -> Database
Edit Event -/ 

我想 aBlockingCollection<Action<Session>>将是这种实现的一个很好的起点。

这是一个粗略的例子(注意这显然是未经测试的):

// Assuming you have a work queue defined as 
public static BlockingCollection<Action<Session>> myWorkQueue = new BlockingCollection<Action<Session>>();

// and your eventargs looks something like this
public class MyObjectUpdatedEventArgs : EventArgs {
    public MyObject MyObject { get; set; }
}

// And one of your event handlers
public MyObjectWasChangedEventHandler(object sender, MyObjectUpdatedEventArgs e) {
    myWorkQueue.Add(s=>SaveOrUpdate(e.MyObject));
}

// Then a thread in a constant loop processing these items could work:
public void ProcessWorkQueue() {
    var mySession = mySessionFactory.CreateSession();
    while (true) {
        var nextWork = myWorkQueue.Take();
        nextWork(mySession);
    }
}

// And to run the above:
var dbUpdateThread = new Thread(ProcessWorkQueue);
dbUpdateThread.IsBackground = true;
dbUpdateThread.Start();
于 2012-07-25T15:49:47.080 回答
2

至少有两个缺点:

  1. 您正在显着降低性能。在繁忙的网络服务器上使用它就像在电影院外面有一群人,但让人们通过一个全人的入口进入。

  2. 会话具有其内部身份映射(缓存)。每个应用程序一个会话意味着内存消耗随着用户访问数据库中的不同数据而增长。最终,您甚至可以最终将整个数据库放在内存中,这当然是行不通的。这需要不时调用一个方法来删除一级缓存。但是,现在还不是删除缓存的好时机。您不能在请求开始时加入,因为其他并发会话可能会受到此影响。

我相信人们会增加其他的缺点。

于 2012-07-25T15:35:37.867 回答