我使用hibernate来处理与DB的连接。我有几个会话工厂连接到不同的模式。
在启动时构建所有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永远不可能。我知道问题是工厂实例变量的静态关键字,并且在构造函数中没有启动。我不希望这个"永远在线"动初始化!它只应在需要时至少初始化一次。
我阅读了一些设计模式和代码质量书,但我很难实现我学到的东西。我想我创造了一种代码味道。我该如何修复这个设计?请解释我的错误以及为什么我的选择有问题。
答案 0 :(得分:1)
我不确定编译器警告(可能由IDE发出而不是javac
)与static
的{{1}}修饰符相关。
实际上getFactory()
实现声明了一个getFactory()
语句,其switch
个案例返回default
:
null
如果传递的参数不允许输入之前的一个案例,那么default:
assert false : "Switch default should not be reachable.";
return null;
可能确实返回getFactory()
。
但我认为null
的主要问题是缺乏线程安全性。实际上,如果多个线程同时访问它,您可能会创建多个会话并可能生成不一致的状态
或者,要按需创建会话,您可以使用单一模式的特定风格:the initialization-on-demand holder idiom:
在软件工程中,按需初始化持有者(设计 成语是一个懒惰的单身人士。在所有版本的Java中, 这个习惯用于实现安全,高度并发的延迟初始化 表现不错。