如何使用Hibernate处理多个数据库模式?

在我的一个项目中,我有一个管理多个客户的应用程序(如果您愿意,还可以管理客户)。 对于它们中的每一个,我在数据库上都有一个专用的模式。 但是,应用程序一次只处理一个客户端,即用户必须在应用程序中从一个客户端切换到另一个客户端(在运行时,不重新启动应用程序)才能从此新客户端访问数据。

对于这种项目,您将如何管理连接以及持久层?

我想使用Hibernate。 在处理多个数据库/模式时,我必须非常小心的要点是什么?

在这种情况下,Spring可以提供任何帮助吗?


如果我不够清楚,让我用一个例子解释一下这种情况。 想象一下,我的应用程序可以处理两个客户端: clientONEclientTWO 。 我已经实现了一个类,它可以为我提供给定客户端的数据库模式,用户,密码和连接字符串。

每个客户都有一个债务人列表,但遗憾的是,DEBTOR表结构对于clientONEclientTWO并不相同。 即使表/列的名称也不一样……

所以我可以为每个客户端创建一个debtor类(我使用Hibernate注释):

 @Entity @Table(name = "T_DEBTOR_ONE") ... public class ClientOneDebtor { @Id @Column(name = "ID_DEBTOR") private String idDebtor; ... } 

和:

 @Entity @Table(name = "T_DEBTOR_TWO") // Table names are not the same among the different schemas... ... public class ClientTwoDebtor { @Id @Column(name = "DEBTOR_ID") // It's just to show that the same information is stored in a column that has not the same name. private String idDebtor; ... } 

理想情况下,我会尝试使用一个通用的Debtor类(这里是一个Abstract类,但我可以使用一个接口):

 public abstract class AbstractDebtor { public abstract String getIdDebtor(); ... } @Entity @Table(name = "T_DEBTOR_ONE") ... public class ClientOneDebtor extends AbstractDebtor { @Id @Column(name = "ID_DEBTOR") private String idDebtor; ... } @Entity @Table(name = "T_DEBTOR_TWO") ... public class ClientTwoDebtor extends AbstractDebtor { @Id @Column(name = "DEBTOR_ID") // It's just to show that the same information is stored in a column that has not the same name. private String idDebtor; ... } 

这样,我就可以更容易地操作DAO / Service层中的Debtor对象,因为我不需要为每个客户端复制我的DAO和服务。 例如,从DAO获取所有债务人列表的方法将是public List getAllDebtors() { ... }

那么,当我更改由我的应用程序管理的客户端时,如何更改上下文? 换句话说,我如何向Hibernate(或Spring?)表明我想使用关于我的应用程序当前管理的客户端的正确持久性对象( ClientOneDebtorClientTwoDebtor )?

如果您认为我走错了方向,请不要犹豫,分享您对如何解决这类问题的看法……


编辑第一个答案:

我需要处理的不同模式的数量大约是15 – 20.除此之外,我只需要映射其表的一小部分。

我也知道每个客户/客户有一个模式不是存储数据的最佳解决方案。 但是,这种架构存在5年以来,我们可能会在明年转移到一个架构(在最好的情况下;))。

如果每次只需要一个,那么它就会变得更加简单。 只需为每个数据库创建一个SessionFactory 。 避免使用HibernateUtils静态SessionFactory实例方法,您将不会遇到任何问题。

如果没有太多数据库(数百个),使用Spring执行此操作的一种巧妙方法是为每个包含特定于该数据库的SessionFactoryBeanDataSource配置的Spring ApplicationContext实例化。

您可以使用PropertyOverrideConfigurer等Spring机制和公共父ApplicationContext来分解所有常见内容,以便您的多个子ApplicationContext都很小且可维护。

然后当请求进入时,只需选择您要使用的ApplicationContext并开始从中提取bean。

如果你想在没有Spring的情况下这样做,你也可以创建多个SessionFactory实例并将“当前”实例存储在静态ThreadLocal

根据我的经验,为不同的客户/用户/公司/其他人设置不同的模式永远不是一个特别好的主意。 你有多少这样的架构? 2? 5? 100?

在我们有两个或更多模式的应用程序中(将它们托管在不同的服务器上或访问由第三方托管的DB作为典型的用例),我们只需为每个模式配置独立的会话工厂。 选择正确的是由注入DAO的会话工厂“隐式完成”。 所以对于你的情况,你可能有一个clientOneDetborDAO和一个clientTwoDebtorDAO – 虽然这对100个客户来说很难;)

遗憾的是,真实世界通常需要多个数据库/模式,尤其是当您的供应商产品的数据库必须与您的公司数据库不同时。

制作任意数量的数据库将是一团糟,为此,您真的应该考虑更好的数据组织forms。 但对于一组固定(希望很小)的数据库,只需在持久性配置中定义它们,每个数据库都有一个单独的PersistenceUnit(这意味着一个单独的EntityManager)。

使用图示的inheritance方案,您可以为每个派生类分配适当的EntityManager,假设框架允许您。