Hibernate @Table Annotation中的动态模式

时间:2015-11-23 03:14:12

标签: java hibernate

想象一下,您在两个环境中有四个MySQL数据库模式:

  • foo(prod db),
  • bar(正在进行的foo db重组,
  • foo_beta(测试数据库),
  • bar_beta(新结构的测试数据库)。

此外,假设您在实体上有一个带有Hibernate注释的Spring Boot应用程序,如下所示:

@Table(name="customer", schema="bar")
public class Customer { ... }

@Table(name="customer", schema="foo")
public class LegacyCustomer { ... }

在本地开发时没问题。您模仿本地环境中的生产数据库表名称。但是,然后你尝试在它上线之前演示功能,并希望将其上传到服务器。你在另一个端口启动另一个应用程序实例,并意识到这个副本需要指向“foo_beta”和“bar_beta”,而不是“foo”和“bar”!该怎么做!

如果您在应用中只使用了一个架构,那么您可以将架构全部放在一起并指定hibernate.default_schema,但是......您正在使用两个架构。那就好了。

Spring EL - e.g。 @Table(name="customer", schema="${myApp.schemaName}")不是一个选项 - (甚至有些傲慢的“没有人需要这个”评论),所以如果动态定义模式是荒谬的,那么它会做什么?除此之外,你知道,首先不要陷入这种荒谬的场景。

3 个答案:

答案 0 :(得分:1)

我通过在Hibernate中添加对自己的架构注释的支持来解决这类问题。通过扩展LocalSessionFactoryBean(或Hibernate 3的AnnotationSessionFactoryBean)来实现它并不是很难。注释看起来像这样

@Target(TYPE)
@Retention(RUNTIME)
public @interface Schema {

    String alias() default "";

    String group() default "";

}

使用

的示例
@Entity
@Table
@Schema(alias = "em", group = "ref")
public class SomePersistent {

}

在弹簧配置中指定了aliasgroup的每个组合的模式名称。

答案 1 :(得分:1)

您可以尝试使用拦截器

public class CustomInterceptor extends EmptyInterceptor {
@Override
    public String onPrepareStatement(String sql) {
          String prepedStatement = super.onPrepareStatement(sql);
          prepedStatement = prepedStatement.replaceAll("schema", "Schema1");
          return prepedStatement;
    }
}

将此拦截器添加为会话对象

Session session = sessionFactory.withOptions().interceptor(new MyInterceptor()).openSession();  

所以发生的事情是,一旦执行onPrepareStatement,就会调用此代码块,并且模式名称将从模式更改为schema1。

答案 2 :(得分:0)

您可以使用orm.xml文件覆盖在注释中声明的设置。配置maven或您用于生成可部署构建工件的任何内容,以便为测试环境创建覆盖文件。