【问题标题】:SessionFactory thread safe issueSessionFactory 线程安全问题
【发布时间】:2013-08-16 02:16:40
【问题描述】:

有时我会在我的网络应用程序中收到此错误堆栈跟踪:

   [ArgumentException: An item with the same key has already been added.]
   System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) +52
   System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) +10695474
   System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) +10
   NHibernate.Util.ThreadSafeDictionary`2.Add(TKey key, TValue value) +93
   NHibernate.Type.TypeFactory.GetType(NullableType defaultUnqualifiedType, Int32 length, GetNullableTypeWithLength ctorDelegate) +88
   NHibernate.Type.TypeFactory.<RegisterDefaultNetTypes>b__c(Int32 l) +82
   NHibernate.Type.TypeFactory.BuiltInType(String typeName, Int32 length) +46
   NHibernate.Mapping.SimpleValue.GetHeuristicType() +168
   NHibernate.Mapping.SimpleValue.get_Type() +49
   NHibernate.Mapping.SimpleValue.IsValid(IMapping mapping) +30
   NHibernate.Mapping.PersistentClass.Validate(IMapping mapping) +87
   NHibernate.Mapping.RootClass.Validate(IMapping mapping) +21
   NHibernate.Cfg.Configuration.ValidateEntities() +183
   NHibernate.Cfg.Configuration.Validate() +13
   NHibernate.Cfg.Configuration.BuildSessionFactory() +36
   Framework.Data.Code.BaseSessionFactoryProvider..ctor() +74
   Framework.Data.Code.SessionFactoryProvider..ctor() +29
   Framework.Data.Code.NestedSessionManager..cctor() +43

我的 SessionFactoryProvider 是线程安全的单调:

 public interface ISessionFactoryProvider
 {
        ISessionFactory GetSessionFactory();
 }
 public abstract class BaseSessionFactoryProvider : ISessionFactoryProvider
 {
        protected readonly ISessionFactory factory;
        public ISessionFactory GetSessionFactory()
        {
            return factory;
        }

        protected BaseSessionFactoryProvider()
        {
            factory = GetConfig().BuildSessionFactory();
        }
        public abstract Configuration GetConfig();
 }
 public class SessionFactoryProvider : BaseSessionFactoryProvider
 {
            public static ISessionFactory SessionFactory
            {
                get { return Instance.factory; }
            }
            public override Configuration GetConfig()
            {
                return new Configuration().Configure();
            }
            public static SessionFactoryProvider Instance
            {
                get
                {
                    return NestedSessionManager.sessionManager;
                }
            }
            class NestedSessionManager
            {
                internal static readonly SessionFactoryProvider sessionManager =
                    new SessionFactoryProvider();
            }
   }

此外,在我的应用程序中,我通过 ninject 将 SessionFactoryProvider 绑定到 ISessionFactoryProvider kernel.Bind&lt;ISessionFactoryProvider&gt;().To&lt;SessionFactoryProvider&gt;().InSingletonScope();

所以我的问题是为什么会出现这个错误?

【问题讨论】:

  • 不要被堆栈跟踪中的ThreadSafeDictionary 误导。我不认为这是一个线程问题。这更有可能是您的 NHibernate 映射的问题。您是否有两个具有相同类名的实体?也许在不同的命名空间中?
  • @DanielSchilling 如果是重复映射,错误不会总是出现,而不是“有时”吗?
  • 恐怕我没有答案...但是您似乎将这个 csharpindepth.com/Articles/General/Singleton.aspx#nested-cctor 的一个稍微不同的版本与继承混合在一起。我在这里看不到任何缺陷(但我不是 C# 忍者)。您还可以将它与您的 IOC 单例实现混合使用。我想问题可能就在这里,你应该只依赖你的 IOC 来实现单例。
  • @jbl,谢谢你的回答。我的映射没问题。是的,我将单音技术与继承相结合。可能吗。我还指出 ninject 在单音范围内为 ISessionFactoryProvider 提供服务。我尝试删除单音范围

标签: nhibernate thread-safety singleton ninject sessionfactory


【解决方案1】:

在我的 cmets 中,我说我在你的 Singleton 实现中没有发现任何缺陷。 事实上,有一个明显的:你的SessionFactoryProvider 无参数构造函数不是私有的,因为SessionFactoryProvider 的构造函数没有任何重载。

所以编译器为SessionFactoryProvider生成了一个公共的无参数构造函数 见Should we always include a default constructor in the class?

所以任何代码都可以通过实例化一个新的SessionFactoryProvider Ninject 使用这个公共构造函数(这应该很容易测试)来实例化类。 (这是让我感到困惑的一点:Ninject 是如何实例化类的?它不应该能够在没有公共构造函数的情况下实例化一个类)。 我想这就是你最终得到重复的SessionFactoryProvider的方式。

您应该使用公共构造函数来实现您的SessionFactoryProvider,而无需考虑单例实现。然后只需依靠 Ninject 及其InSingletonScope() 来提供单例功能

【讨论】: