【问题标题】:How to remove code smell: getSessionFactory, create SessionFactory only when necessary如何去除代码异味:getSessionFactory,仅在必要时创建 SessionFactory
【发布时间】:2018-06-12 20:08:41
【问题描述】:

我使用休眠来处理与数据库的连接。我有几个连接到不同模式的会话工厂。

在启动时构建所有 SessionFactory 至少需要 60 秒。所以我只在必要时建造它们:

public class HibernateUtil {
    private static SessionFactory factory_db1;
    private static SessionFactory factory_db2;
    //...

    public enum DbSchema {
      db1, db2 //...
    }        

    private createSessionFactory(Configuration conf){
    //...
    }

    public static SessionFactory getFactory(DbSchema dbSchema) {

      try {
        switch (dbSchema) {
            case db1:
                if (factory_db1== null){
                    Configuration conf = new Configuration().configure(HIBERNATE_CFG_DB1);
                    factory_db1= createSessionFactory(conf);
                }
                return factory_db1;
            case db2:
                if (factory_db2 == null){
                    Configuration conf = new Configuration().configure(HIBERNATE_CFGXML_DB2);
                    factory_ooarchive = createSessionFactory(conf);
                }
                return factory_ooarchive;
            //... more factories created
            default:
                assert false : "Switch default should not be reachable.";
                return null;
        }
      } catch (Throwable ex) {
        log.error("Failed to initialize SessionFactory." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

现在当我访问这个工厂时:

Session session = HibernateUtil.getFactory(db1).openSession();
// **Compiler warning: method invocation may produce java.lang.nullpointerexception**

只有通过 getFactory() 方法才能获得工厂,因此我认为 NPE 永远不可能。我知道问题是工厂实例变量的静态关键字,并且构造函数中没有初始化。我不想要这种“永远在线”的初始化!它应该只在需要时至少初始化一次。

我阅读了一些设计模式和代码质量方面的书籍,但我很难实施所学的内容。我想我创造了一种代码味道。我该如何解决这个设计?请解释我的错误以及为什么我的选择有问题。

【问题讨论】:

    标签: java hibernate oop design-patterns factory


    【解决方案1】:

    我不确定编译器警告(可能由 IDE 而不是javac 发出)与getFactory()static 修饰符有关。

    实际上getFactory() 实现声明了一个switch 语句,它有一个default 的情况,返回null

    default:
        assert false : "Switch default should not be reachable.";
        return null;
    

    所以getFactory() 可能确实返回null 如果传递的参数不允许在前面的一种情况下输入。

    但我认为getFactory() 的主要问题是它缺乏线程安全性。实际上,如果多个线程同时访问它,您可能会创建多个会话,并且可能会生成不一致的状态。
    作为替代方案,要按需创建会话,您可以使用特定风格的单例模式:the initialization-on-demand holder idiom

    在软件工程中,按需初始化持有者(设计 pattern) idiom 是一个延迟加载的单例。在所有版本的 Java 中, 该成语启用了一个安全的、高度并发的延迟初始化 表现不错。

    【讨论】:

    • 是的,你是对的。我没有考虑线程安全。作为一个快速而肮脏的解决方案,我向 HibernateUtil 类中的所有方法添加了同步。对于完整的解决方案,我将实施您提到的成语。似乎是惰性初始化的最佳选择。
    • 您确实应该这样做,因为如果该方法被非常频繁地调用,它可能会通过使所有方法同步而产生一些延迟。
    • 我同意,这就是为什么经过一点思考我已经实现了它!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2011-06-19
    • 2014-10-28
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    相关资源
    最近更新 更多