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

Posted

技术标签:

【中文标题】如何使用 Hibernate 处理多个数据库模式?【英文标题】:How to handle several DB schemas with Hibernate? 【发布时间】:2010-12-12 08:33:06 【问题描述】:

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

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

我想为此使用 Hibernate。在处理多个数据库/模式时,我必须非常小心哪些点?

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


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

每个客户都有一个债务人列表,但不幸的是,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 类(这里是一个抽象类,但我可能会使用一个接口):

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 / 服务层中操作 Debtor 对象,因为我不需要为每个客户端复制我的 DAO 和服务。 例如,DAO 获取所有债务人列表的方法是public List<AbstractDebtor> getAllDebtors() ...

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

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


编辑第一个答案:

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

我还知道,每个客户/客户拥有一个架构并不是存储数据的最佳解决方案。但是,这种架构已经存在 5 年了,我们可能会在明年只迁移到一个架构(在最好的情况下;))。

【问题讨论】:

【参考方案1】:

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

如果您没有太多(数百个)数据库,那么使用 Spring 执行此操作的一种巧妙方法是为每个包含专门用于该数据库的 SessionFactoryBeanDataSource 配置的单独的 Spring ApplicationContext 实例化.

您可以使用 PropertyOverrideConfigurer 和公共父级 ApplicationContext 之类的 Spring 机制来分解所有常见的东西,这样您的许多子 ApplicationContexts 就很小且可维护。

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

如果您想在没有 Spring 的情况下执行此操作,您还可以创建多个 SessionFactory 实例并将“当前”实例存储在静态 ThreadLocal 中。

【讨论】:

【参考方案2】:

不幸的是,现实世界通常确实需要多个数据库/架构,尤其是当您的供应商产品的数据库必须与您的公司数据库不同时。

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

使用您说明的继承方案,假设框架允许您将适当的 EntityManager 分配给每个派生类。

【讨论】:

以上是关于如何使用 Hibernate 处理多个数据库模式?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过使用 JPA + Hibernate 和 Spring-boot 在一个数据库中使用多个模式?

如何在 Spring Boot 中使用 Hibernate/JPA 返回多级 json

如何在 Spring 生态系统中使用 JPA hibernate 连接到不同的 mysql 数据库模式?

Hibernate的批量处理

Spring批量启动多个数据源多个模式

如何将多个文件模式加载到数据库中?