문제

나는 한동안 NHibernate를 사용해 왔으며 때때로 두 페이지를 동시에(또는 가능한 한 가깝게) 요청하려고 하면 오류가 발생한다는 것을 발견했습니다.그래서 나는 세션 관리가 스레드로부터 안전하지 않기 때문이라고 생각했습니다.

내 수업인 줄 알고 이 블로그 포스팅과 다른 방법을 사용해 봤습니다. http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/ 그러나 나는 여전히 같은 문제를 겪습니다.내가 얻는 실제 오류는 다음과 같습니다.

Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed

datareader가 열려 있거나 열려 있지 않지만 이것이 주요 원인입니다.

아래에 세션 관리 클래스를 배치했습니다. 왜 이러한 문제가 발생하는지 알 수 있는 사람이 있습니까?

public interface IUnitOfWorkDataStore
{
    object this[string key] { get; set; }
}


    public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
    {
        if (storage == null)
            throw new Exception("storage mechanism was null but must be provided");

        Configuration cfg = ConfigureNHibernate(string.Empty);
        foreach (Assembly assembly in assemblies)
        {
            cfg.AddMappingsFromAssembly(assembly);
        }

        SessionFactory = cfg.BuildSessionFactory();
        ContextDataStore = storage;

        return cfg;
    }

    public static ISessionFactory SessionFactory { get; set; }
    public static ISession StoredSession
    {
        get
        {
            return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
        }
        set
        {
            ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
        }
    }

    public const string CDS_NHibernateSession = "NHibernateSession";
    public const string CDS_IDbConnection = "IDbConnection";

    public static IUnitOfWorkDataStore ContextDataStore { get; set; }

    private static object locker = new object();
    public static ISession Current 
    {
        get 
        {
            ISession session = StoredSession;

            if (session == null) 
            {
                lock (locker)
                {
                    if (DBConnection != null)
                        session = SessionFactory.OpenSession(DBConnection);
                    else
                        session = SessionFactory.OpenSession();

                    StoredSession = session;
                }
            }

            return session;
        }
        set
        {
            StoredSession = value;
        }
    }

    public static IDbConnection DBConnection
    {
        get
        {
            return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
        }
        set
        {
            ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
        }
    }

}

제가 사용하고 있는 실제 매장은 다음과 같습니다.

public class HttpContextDataStore : IUnitOfWorkDataStore
{
    public object this[string key]
    {
        get { return HttpContext.Current.Items[key]; }
        set { HttpContext.Current.Items[key] = value; }
    }
}

다음을 사용하여 Application_Start에서 SessionFactory를 초기화합니다.

NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] { 
                typeof(MappedClass).Assembly});

업데이트

안녕하세요 여러분, 조언해 주셔서 감사합니다. 코드를 단순화하기 위해 몇 가지 다른 방법을 시도했지만 여전히 동일한 문제에 직면하고 있으며 그 이유를 알 수 있습니다.

필요할 때마다 요청별로 세션을 생성하지만 global.asax에서는 Application_EndRequest의 세션을 삭제합니다.그러나 페이지 로드가 끝날 때 디버그하는 동안 Application_EndRequest가 두 번 이상 실행되는 것을 발견했습니다.나는 이벤트가 요청이 끝날 때 한 번만 발생한다고 생각했지만 그렇지 않고 다른 항목이 이상한 이유로 세션(오류가 불평하는 것)을 사용하려고 시도하고 있다고 생각했습니다. 내 문제이고 세션은 여전히 ​​스레드로부터 안전하므로 조기에 폐기됩니다.

누구든지 아이디어가 있나요?Google을 검색한 결과 VS 개발 서버가 이와 같은 문제를 일으키는 것을 확인했지만 IIS를 통해 실행하고 있습니다.

도움이 되었습니까?

해결책

나는 당신의 전체 코드베이스나 당신이 해결하려는 문제를 보지 못했지만 NHibernate를 어떻게 사용하고 있는지 다시 생각하는 것이 순서일 수 있습니다.로부터 선적 서류 비치:

nhibernate 세션을 만들 때 다음과 같은 관행을 관찰해야합니다.

  • 데이터베이스 연결 당 하나 이상의 동시 ISESSION 또는 ITRANSACTION 인스턴스를 작성하지 마십시오.

  • 트랜잭션 당 데이터베이스 당 하나 이상의 ISESSION을 만들 때 매우주의하십시오.issession 자체는로드 된 객체에 대한 업데이트를 추적하므로 다른 issession은 오래된 데이터를 볼 수 있습니다.

  • ISession은 ~ 아니다 스레드세이프! 두 개의 동시 스레드에서 동일한 issession에 액세스하지 마십시오.assession은 보통 a입니다 단일 작업 단위!

마지막 부분은 내가 말하는 내용과 가장 관련이 있고 다중 스레드 환경의 경우 중요합니다.ISession은 소규모 원자성 작업을 위해 한 번 사용한 후 삭제되어야 합니다.또한 문서에서 :

IsessionFactory는 모든 응용 프로그램 스레드에서 공유 할 수있는 비용이 많이 드는 스레드 사프 객체입니다.ISESSION은 단일 비즈니스 프로세스에 한 번 사용해야하는 저렴한 비 스레드 안전 객체입니다.

ISession 자체를 저장하는 대신 이 두 가지 아이디어를 결합하는 것이 "큰" 개체이기 때문에 세션 팩토리를 저장합니다.그런 다음 SessionManager.GetSession()과 같은 것을 래퍼로 사용하여 세션 저장소에서 팩토리를 검색하고 세션을 인스턴스화하여 하나의 작업에 사용할 수 있습니다.

ASP.NET 응용 프로그램의 컨텍스트에서는 문제가 덜 명확해집니다.ISession 개체의 범위를 정적으로 지정합니다. 이는 해당 개체가 AppDomain 전체에서 공유된다는 의미입니다.해당 AppDomain의 수명 내에 두 개의 다른 페이지 요청이 생성되어 동시에 실행되는 경우 이제 동일한 ISession을 접촉하는 두 개의 페이지(다른 스레드)가 있습니다. ~ 아니다 안전한.

기본적으로 세션을 가능한 한 오랫동안 유지하려고 하기보다는 가능한 한 빨리 세션을 제거하고 더 나은 결과가 있는지 확인하십시오.

편집하다:

좋아, 당신이 이걸 가지고 어디로 가려고 하는지 알겠어요.Open Session In View 패턴을 구현하려는 것처럼 들리는데, 이를 수행할 수 있는 몇 가지 다른 경로가 있습니다.

다른 프레임워크를 추가하는 것이 문제가 되지 않으면 다음과 같은 것을 살펴보십시오. 스프링.NET.모듈식이므로 전체를 사용할 필요가 없으며 NHibernate 도우미 모듈만 사용할 수 있습니다.뷰 패턴에서 오픈 세션을 지원합니다.선적 서류 비치 여기 (제21.2.10."웹 세션 관리").

직접 만들고 싶다면 Bill McCafferty가 게시한 이 코드 프로젝트를 확인하세요. "NHibernate 모범 사례".마지막에는 사용자 정의 IHttpModule을 통해 패턴을 구현하는 방법을 설명합니다.또한 인터넷에서 IHttpModule 없이 패턴을 구현하는 방법에 대한 게시물을 본 적이 있지만 여러분도 그렇게 하려고 했을 수도 있습니다.

나의 일반적인 패턴(여기서는 이미 건너뛰었을 수도 있음)은 프레임워크를 먼저 사용하는 것입니다.그것은 많은 두통을 제거합니다.너무 느리거나 내 요구 사항에 맞지 않으면 구성을 조정하거나 사용자 정의하려고 합니다.그 후에야 나는 내 자신의 롤을 시도하지만 YMMV.:)

다른 팁

NHibernate에서는 (Java Hibernate 사용자이기 때문에) 확신할 수 없지만 최대 절전 모드에서는 Session 개체가 설계상 스레드로부터 안전하지 않습니다.세션을 열고 닫아야 하며 세션이 현재 스레드의 범위를 벗어나도록 허용해서는 안 됩니다.

나는 '세션 보기 열기'와 같은 패턴이 .Net 어딘가에 구현되었다고 확신합니다.

또 다른 흥미로운 문제는 세션에 최대 절전 모드 엔터티를 넣을 때입니다.여기서 문제는 요청이 완료되면 연결된 세션이 닫히거나 닫혀야 한다는 것입니다.로드되지 않은 연결을 탐색하려면 엔터티를 새(최대 절전 모드) 세션에 다시 연결해야 합니다.두 개의 세션에 엔터티를 연결하려고 하면 두 개의 요청이 동시에 이 작업을 수행하려고 하면 문제가 발생하는 경우 자체적으로 새로운 문제가 발생합니다.

도움이 되었기를 바랍니다.가레스

문제는 제어 반전을 위한 내 라이브러리가 HTTP 컨텍스트에서 생성되는 개체를 올바르게 관리하지 않아서 해당 컨텍스트에서 사용할 수 없어야 하는 개체에 대한 참조를 얻고 있다는 것입니다.이것은 Ninject 1.0을 사용하고 있었는데, Ninject 2.0(베타)으로 업데이트하면 문제가 해결되었습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top