我正在处理的应用程序有一个维护数据库连接的类。此类的所有成员都是静态的,以强制执行类似单一的模式,因此实际的连接逻辑在静态初始化程序块中执行:
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
sessionFactory = new Configuration().configure().buildSessionFactory();
}
static void openSession() {
//open session with sessionFactory
}
public static Session currentSession() {
//return the currently open session
}
static void closeSession() {
//close the currently open session
}
}
但是,应用程序现在需要打开与第二个数据库的数据库连接。现在这个类的结构方式,在保持上述模式的同时维持第二个连接的唯一方法是创建第二个类(类似于SecondHibernateUtil)并更改初始化块中的一行配置。这感觉真的是浪费了大量的复制/粘贴。
任何人都可以提出一种方法,我可以重新设置此设置以同时维护多个连接,同时不会对已调用现有方法的代码过度破坏吗?
答案 0 :(得分:2)
首先,它可能不应该是静态的。
答案 1 :(得分:2)
保留静态方法并让它们委托给默认实例的相应实例方法。
对于辅助数据库,允许通过任何方式创建更多实例,并通过其实例方法访问它们。
然后你可以去掉静态方法的调用者,当它们全部消失时删除静态方法。
答案 2 :(得分:1)
嗯,现在是正确的事情。
无法添加第二个连接并保留您描述的模式。
相反,你可能会尝试把事情搞定。
您有两种选择。
第一个选项。保持一团糟,让它变得有点糟糕(不告诉你的客户)
创建新的连接实用程序(HibernateUtility2)并使用该新的实用程序对象。
// Create a new utility class using a map instead.
class HibernateUtility {
private Map<String, SessionFactory> factories;
private HibernateUtility instance;
public static HibernateUtility getInstance() {
if( instance == null ) {
instance = new HibernateUtility();
}
return instance;
}
private HibernateUtility() {}
private void check( String whichConnection ) {
if( !factories.containsKey( whichConnection ) ) {
// start the connection
factories.put( whichConnection, new Configu..
//... etc etc ().configure().buildSessionFactory() );
}
}
void openSession( String whichConnection ) {
check( whichConnection );
//open session with sessionFactory
factories.get( whichConnection ).open(); //etcetc
}
Session currentSession( whichConnection ) {
check( whichConnection );
//return the currently open session
factories.get( whichConnection ) .....
}
void closeSession( String whichConnection ) {
check( whichConnection );
//close the currently open session
factories.get( whichConnection );
}
}
//------------------------------------------
// Make your existing class call that class
public class HibernateUtil {
static void openSession() {
//open session with sessionFactory
HibernateUtility.getInstance( "one" ).openSession();
}
public static Session currentSession() {
//return the currently open session
HibernateUtility.getInstance( "one" ).currentSession();
}
static void closeSession() {
//close the currently open session
HibernateUtility.getInstance( "one" ).closeSession();
}
}
//------------------------------------------
// Make the new connection use that class too.
public class HibernateUtil {
static void openSession() {
//open session with sessionFactory
HibernateUtility.getInstance( "two" ).openSession();
}
public static Session currentSession() {
//return the currently open session
HibernateUtility.getInstance( "two" ).currentSession();
}
static void closeSession() {
//close the currently open session
HibernateUtility.getInstance( "two" ).closeSession();
}
}
这样现有的客户端代码就不会中断。
第二个选项。清理混乱并相应地修改代码。
在第二个选项中,您创建的对象与之前描述的HibernateUtility非常相似,但这次您不添加方法 openSession ,也不添加 closeSession 。属于那个界面。
使用这种非静态方法,您可以创建可以连接到不同配置的不同实例。
你只需使用 currentSession ,如果会话不存在,则创建一个新的,并作为参数接收一个标识符(很像前一个示例中的“one”和“two”)
在第二个选项中,您必须更改客户端代码以使用正确的实现。
注意: SO中的代码格式错误,我花了一些时间来格式化它,它看起来不是很好:(
答案 3 :(得分:1)
我很久以前就看过这个问题而且由于你提出的确切问题,我决定永远不要制作这样的静态课程。实际上有2个问题...
首先它不可重用(正如你所注意到的)并且修复它是一个艰难的重构。
其次,你不能拥有第二个实例(似乎程序员认为只有一个东西,他们认为他们永远不需要改变日期的前两位数!)
如果您决定要使用工厂模式(或类似spring)的第二个实例,这是一个微不足道的更改 - 只需将变量传递给工厂以指示您想要的实例 - 但是要从静态重构上课只是个婊子。
你甚至应该小心不要滥用工厂模式。如果你真的倾向于那个方向,学习并接受春天 - 它将与你的自然倾向相结合,以改善你的代码。
答案 4 :(得分:0)
有一种不太好的方式,有时除了复制整个销售课程并与复制品一起生活外,没有其他真正的选择。
我知道这听起来确实糟糕但是自从它从hibernate文档中复制以来,这个类实际上有多少次改变了?
我确定有人会建议将整个应用程序转换为Spring SessionFactory
以及所有这些东西,但除非您的应用程序是Hibernate“Hello World”,否则我猜这可能需要一点时间超过几个小时。
答案 5 :(得分:0)
学习春天。如果你已经在使用Hibernate,那么学习足够的Spring来处理这个问题并不是一件容易的事。 Spring Source的人们已经比以往更好地解决了这个问题。
Spring事务对JDBC,Hibernate,iBatis或Spring支持的任何其他持久性技术都有效。如果您已经在使用Spring,请不要重新发明他们已经做得更好的事情。使用他们的交易。
如果你有多个数据库,并且你作为一个单独的工作单元执行写入操作,那么你就足够了解两者的XA驱动程序,对吗?
答案 6 :(得分:0)
有两种可能的答案;让我们看看两者。
一种是将其转换为非静态。可以说这首先比静态接口更好,因为你在接口后面有一个具体的对象(SessionFactory)。这样做的好处是你可以推迟创建SessionFactory直到你需要它(如果你不这样做,就永远不会创建它)。创建一个静态方法来获取默认的HibernateUtil对象,如果不存在则创建它。您可能想要或不想要第二个HibernateUtil。
另一种方法是创建一个全新的静态对象HibernateUtil2,它在必要时委托给HibernateUtil。但请注意,这些不会以任何类似继承的方式相互关联,因为静态不能在接口中使用。
我会推荐第一条路线,其他条件相同,但您的具体情况可能需要第二条路线。
答案 7 :(得分:0)
解决这个问题的破坏性最小的方法是将第二个静态变量添加到类中,在静态块中初始化第二个SessionFactory,然后修改“currentSession”静态方法以使用String参数根据您的业务选择适当的实例/代码逻辑。
答案 8 :(得分:0)
我不知道这个问题的一般解决方案,但是在这里你可以声明非静态SessionFactory
并在代码中设置配置,而不是在hibernate.cfg.xml
文件中!所以你可以有多个SessionFactory
连接到多个数据库以获得更多不同的映射。