简体   繁体   中英

NHibernate timeout with SQL Server

I have an ASP.Net application with backend in C# that is using NHibernate with SQL Server.

Recently I have noticed that during a long time doing some tasks in a certain page of the web, it freezes and a timeout comes in (NHibernate exception).

After the timeout problem I go to SQL Server Management Studio and I can see in the monitor how there are like dozens of processes without any state and all to the same database:

SQL Server监视器中的进程

I have searched for solutions everywhere, and I don't know if I'm probably disposing the session incorrectly. Here is how I dispose the session:

public static void DisposeSession()
{
    FlushSession(true); // Method that does a commit if there is a transaction
    ISession Session = CurrentSessionContext.Unbind(sessionFactory);

    if (Session != null)
    {
        Session.Close();
        Session.Dispose();
    }
}

Edit 1:

I'm currently using WebForms and there are no shared sessions between requests, sessions are being disposed correctly.

The problem is when I start going though different parts of my web (so doing new requests), the processes start growing like in the image... and at a certain point, the webpage responds with a runtime error or timeout.

How can I control this behaviour? It's possible only to have one process per request and when disposing, closing the process?

Edit 2:

I was wrong, the session management is done right with the method provided in the first answer. There are processes but they are correctly managed by NHibernate.

First, ensure your CurrentSessionContext does not share session among requests.

Typically this kind of context stores session in the HttpContext.Current.Items dictionary. This is a safe place for ensuring it will not end up shared with other http requests.
If instead it shares session between requests, your application would fail for most users once under load.
If it uses a ThreadContext or a CallContext , it will regularly fails for some requests under load, due to "ASP.Net thread agility" causing some http request to switch threads and lose their previous ThreadContext and CallContext . HttpContext.Current.Items is guaranteed to be preserved when a http request switches threads, not those other ones.

If this CurrentSessionContext looks right, then fix your DisposeSession . It does not ensure your session will be closed in case of a failed flush.

It should probably be more like:

public static void DisposeSession()
{
    try    
    {    
        FlushSession(true); // Method that does a commit if there is a transaction
    }
    finally
    {
        ISession Session = CurrentSessionContext.Unbind(sessionFactory);

        if (Session != null)
        {
            // Dispose closes the session too. And Close dispose the transaction
            // if there was one. And transaction Dispose rollbacks if it was pending.
            Session.Dispose();
        }
    }
}

Then, check this DisposeSession is always called whatever the way your request ends. Especially check what happens on requests triggering an exception. This include some redirect cases which work with a ThreadAbortException , like Response.Redirect("...") .

Session management:

About the session management pattern I usually use, I bound it to dependency injection, with a per request life cycle and an http module ensuring it gets disposed whatever the outcome of the request, with transaction handled by an action filter (MVC).

Your pattern is far from that. If you wish to change it, you may have it easier following this blog post series from an old timer contributor to NHibernate and author of NHibernate profiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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