gpt4 book ai didi

asp.net - 带 session 的 NHibernate 线程安全

转载 作者:行者123 更新时间:2023-12-04 00:18:46 25 4
gpt4 key购买 nike

我已经使用 NHibernate 一段时间了,并且不时发现如果我尝试同时请求两个页面(或尽可能接近),它偶尔会出错。所以我认为这是因为我的 session 管理不是线程安全的。
我以为这是我的课,所以我尝试使用与这篇博文不同的方法 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
要么打开要么没有打开数据读取器,但这是罪魁祸首。
我把我的 session 管理类(class)放在下面,有人能发现我为什么会遇到这些问题吗?
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});
更新
谢谢你的建议。我尝试了一些不同的方法来尝试简化代码,但我仍然遇到相同的问题,我可能知道原因。
我在需要时为每个请求创建 session ,但在我的 global.asax 中,我正在处理 Application_EndRequest 上的 session 。但是,当我在加载页面结束时进行调试时,我发现 Application_EndRequest 被多次触发。我认为该事件只假设在请求结束时触发一次,但如果不是,并且其他一些项目正在尝试使用 Session (这是错误所提示的),无论出于什么奇怪的原因可能是我的问题, session 仍然是线程安全的,它只是被提前处理掉了。
有人有什么想法吗?我做了一个谷歌,看到 VS 开发服务器确实会导致这样的问题,但我是通过 IIS 运行它。

最佳答案

虽然我还没有看到你的整个代码库或你试图解决的问题,但重新思考你如何使用 NHibernate 可能是正确的。来自 documentation :

You should observe the following practices when creating NHibernate Sessions:

  • Never create more than one concurrent ISession or ITransaction instance per database connection.

  • Be extremely careful when creating more than one ISession per database per transaction. The ISession itself keeps track of updates made to loaded objects, so a different ISession might see stale data.

  • The ISession is not threadsafe! Never access the same ISession in two concurrent threads. An ISession is usually only a single unit-of-work!



最后一点与我所说的最相关(在多线程环境的情况下也很重要)。一个 ISession 应该被用于一个小的原子操作,然后被释放。同样来自文档:

An ISessionFactory is an expensive-to-create, threadsafe object intended to be shared by all application threads. An ISession is an inexpensive, non-threadsafe object that should be used once, for a single business process, and then discarded.



结合这两个想法,而不是存储 ISession 本身,存储 session 工厂,因为那是“大”对象。然后,您可以使用类似 SessionManager.GetSession() 作为包装器从 session 存储中检索工厂并实例化 session 并将其用于一项操作。

该问题在 ASP.NET 应用程序的上下文中也不太明显。您正在静态地确定 ISession 对象的范围,这意味着它在 AppDomain 中共享。如果在该 AppDomain 的生命周期内创建了两个不同的页面请求并同时执行,那么您现在有两个页面(不同的线程)接触同一个 ISession,这是不安全的。

基本上,与其尝试尽可能长时间地保持 session ,不如尝试尽快摆脱​​它们,看看是否有更好的结果。

编辑:

好的,我可以看到你想用这个去哪里。听起来您正在尝试实现 Open Session In View 模式,并且您可以采取几种不同的路线:

如果添加另一个框架不是问题,请查看 Spring.NET 之类的内容。 .它是模块化的,所以你不必使用整个东西,你可以只使用 NHibernate 辅助模块。它支持 View 模式中的打开 session 。文档 here (标题 21.2.10.“Web session 管理”)。

如果您想自己动手,请查看 Bill McCafferty 发布的这个代码项目: "NHibernate Best Practices" .最后,他描述了通过自定义 IHttpModule 实现该模式。我还在 Internet 上看到了关于在没有 IHttpModule 的情况下实现该模式的帖子,但这可能是您一直在尝试的。

我通常的模式(也许你已经在这里跳过了)首先使用框架。它消除了很多头痛。如果它太慢或不符合我的需求,那么我会尝试调整配置或自定义它。只有在那之后我才尝试推出自己的,但 YMMV。 :)

关于asp.net - 带 session 的 NHibernate 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/629719/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com