oracle - JPA根据请求参数更改实体表名称

标签 oracle spring-boot jpa

我们的数据库目前有 2 种模式,一种用于生产,一种用于测试,相同的表但不同的数据。

对于服务器端,我们使用 RoutingDatasource 来管理数据。每个请求都有一个参数来知道要访问哪个数据库,例如“prod”或“test”。然后该参数存储在 ThreadLocal 中。我们的 RoutingDatasource 将获取此参数,根据该值并返回正确的数据源。因此,对于两种模式中的同一张表,我们只需要一个映射实体和一个 CrudRepository 。

但由于某些(愚蠢的)原因,我们被要求将两个模式合并为一个模式,每个表前面都有一个前缀,例如 PROD_TABLE1、TEST_TABLE1、PROD_TABLE2、TEST_TABLE2 等。

所以我想问,有这个要求,我们如何才能为每个表只保留 1 个实体、1 个存储库?我们不想克隆代码,创建太多的类继承现有的类只是为了映射到第二个表。 @SecondaryTable 似乎不是我们想要的。

=================================

更新1:

我正在查看PhysicalNamingStrategy,能够为表名添加前缀。但这仅在初始化 EntityManager 时运行一次。那么有没有其他方法可以在每个请求的表中添加前缀?

=================================

更新2: 我尝试这样的事情:

@Table(name = "##schema##TABLE1")

然后在我们的项目中添加一个Hibernate拦截器。在准备语句时,我们从ThreadLocal获取参数,然后用正确的前缀替换“##schema##”部分。使用这种方式,一切正常,但我不太喜欢这个解决方案。

谁有更好的方法吗?

最佳答案

将我自己的解决方法放在这里,供任何需要的人使用:

首先在每个实体对象中添加前缀“##prefix##”:

@Table(name = "##prefix##TEST_TABLE_1")

创建一个 Hibernate 拦截器类,扩展 EmptyInterceptor 并重写方法 onPrepareStatement。这里从ThreadLocal中获取前缀(预先收到请求时设置)并替换为表名中的“##prefix##”。

public class HibernateInterceptor extends EmptyInterceptor {

    @Override
    public String onPrepareStatement(String sql) {
        String prefix = ThreadLocal.getDbPrefix();
        sql = sql.replaceAll("##schema##", prefix + "_");
        return super.onPrepareStatement(sql);
    }
}

这样,查询将指向正确的表。

并配置到EntityManagerFactory:(您也可以在xml文件中设置)

properties.put("hibernate.ejb.interceptor", "mypackage.HibernateInterceptor");

关于oracle - JPA根据请求参数更改实体表名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51417368/

相关文章:

java - Spring Boot - 自定义 JSON 序列化

java - JPA:单例实体

sql - Oracle SQL 组按 10 分钟时间间隔的行计数

java - Thymeleaf 中的月份本地化

oracle - 在oracle中估计索引创建时间

java - 在 Spring Boot 应用程序中创建自定义连接池

java - 如何以编程方式验证 JPQL(JPA 查询)

java - 我应该包含 JPA 的 main 方法吗?

Oracle - 将字符串转换为时间戳

oracle - 创建oracle包遇到PLS-00103 : Encountered the symbol "CREATE"