简体   繁体   English

在存储库线程中锁定单个会话是否安全? (NHibernate)

[英]Is locking single session in repository thread safe? (NHibernate)

I read many posts saying multithreaded applications must use a separate session per thread. 我读过很多文章,说多线程应用程序每个线程必须使用一个单独的会话。 Perhaps I don't understand how the locking works, but if I put a lock on the session in all repository methods, would that not make a single static session thread safe? 也许我不了解锁定的工作原理,但是如果我在所有存储库方法中的会话上设置了锁定,那将不会使单个静态会话线程安全吗?

like: 喜欢:

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

EDIT: 编辑:

Please consider the context/type of applications I'm writing: 请考虑我正在编写的应用程序的上下文/类型:

Not multi-user, not typical user-interaction, but a self-running robot reacting to remote events like financial data and order-updates, performing tasks and saves based on that. 不是多用户,不是典型的用户交互,而是一个自运行的机器人,对诸如财务数据和订单更新之类的远程事件做出反应,基于此执行任务并进行保存。 Intermittently this can create clusters of up to 10 saves per second. 间歇性地创建每秒最多可节省10次的群集。 Typically it's the same object graph that needs to be saved every time. 通常,它是每次都需要保存的同一对象图。 Also, on startup, the program does load the full database into an entity-object-graph. 同样,在启动时,程序确实将整个数据库加载到实体对象图中。 So it basically just reads once, then performs SaveOrUpdates as it runs. 因此,它基本上只读取一次,然后在运行时执行SaveOrUpdates。

Given that the application is typically editing the same object graph, perhaps it would make more sense to have a single thread dedicated to applying these edits to the object graph and then saving them to the database, or perhaps a pool of threads servicing a common queue of edits, where each thread has it's own (dedicated) session that it does not need to lock. 假设应用程序通常在编辑相同的对象图,那么拥有一个专用于将这些编辑应用于对象图然后将其保存到数据库的线程,或者可能是为公共队列服务的线程池可能更有意义。编辑,每个线程都有它自己的(专用)会话,不需要锁定。 Look up producer/consumer queues (to start, look here ). 查找生产者/消费者队列(首先,请看这里 )。

Something like this: 像这样:

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

I'd imagine that a BlockingCollection<Action<Session>> would be a good starting point for such an implementation. 我以为BlockingCollection<Action<Session>>将是此类实现的一个很好的起点。

Here's a rough example (note this is obviously untested): 这是一个粗糙的示例(请注意,这显然未经测试):

// 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();

At least two disadvantages are: 至少两个缺点是:

  1. You are reducing the performance significantly. 您将大大降低性能。 Having this on a busy web server is like having a crowd outside a cinema but letting people go in through a person-wide entrance. 将其放在繁忙的Web服务器上就像在电影院外面有一群人,但是却使人们可以通过整个人的入口进入。

  2. A session has its internal identity map (cache). 会话具有其内部身份映射(缓存)。 A single session per application means that the memory consumption grows as users access different data from the database. 每个应用程序只有一个会话,这意味着随着用户从数据库访问不同的数据,内存消耗也会增加。 Ultimately you can even end up with the whole database in the memory which of course would just not work. 最终,您甚至可以将整个数据库存储在内存中,这当然是行不通的。 This requires then calling a method to drop the 1st level cache from time to time. 然后,这需要调用一种方法来不时删除第一级缓存。 However, there is no good moment to drop the cache. 但是,没有好时机删除缓存。 You just can't drop in at the beginning of a request because other concurrent sessions could suffer from this. 您只是不能在请求开始时就加入,因为其他并发会话可能会因此受到影响。

I am sure people will add other disadvantages. 我相信人们还会增加其他不利条件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM