我读过很多帖子说多线程应用程序必须为每个线程使用一个单独的 session 。也许我不明白锁定是如何工作的,但是如果我在所有存储库方法中锁定 session ,那不会使单个静态 session 线程安全吗?
喜欢:
public void SaveOrUpdate(T instance)
{
if (instance == null) return;
lock (_session)
using (ITransaction transaction = _session.BeginTransaction())
{
lock (instance)
{
_session.SaveOrUpdate(instance);
transaction.Commit();
}
}
}
编辑:
请考虑我正在编写的应用程序的上下文/类型:
不是多用户,也不是典型的用户交互,而是一个自动运行的机器人,它对财务数据和订单更新等远程事件使用react,并据此执行任务和保存。这可以间歇性地创建每秒最多 10 次保存的集群。通常,每次都需要保存同一个对象图。此外,在启动时,程序会将完整的数据库加载到实体对象图中。所以它基本上只读取一次,然后在运行时执行 SaveOrUpdates。
请您参考如下方法:
鉴于应用程序通常正在编辑相同的对象图,也许让一个线程专用于将这些编辑应用到对象图然后将它们保存到数据库中,或者可能是一个线程池服务更有意义一个公共(public)的编辑队列,其中每个线程都有自己的(专用) session ,不需要锁定。查找生产者/消费者队列(首先,查看 here )。
像这样:
[Producer Threads]
Edit Event -\ [Database Servicer Thread]
Edit Event ------> Queue -> Dequeue and Apply to Session -> Database
Edit Event -/
我想象一个 BlockingCollection<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();
