如何在Spring Boot应用程序中添加非标准化的sql函数?

时间:2016-08-19 14:37:56

标签: hibernate spring-boot spring-data-jpa sql-function

我的应用程序需要在Postgres,Mysql和测试Hsqldb之间移植。我已经设置了Flyway来为这三个提供一些自定义函数,我现在想在我的SQL / HQL查询中使用它。

我当前的设置是使用我在Dialect之间切换的单独application-{profile}.yml;哪个有效,但函数声明需要在各种方言中重复,感觉不是最理想的。

在Hibernate文档中查看15.29. Non-standardized functions,它说我应该使用org.hibernate.cfg.Configuration#addSqlFunction(),它看起来更便携,无需扩展所有三种方言。

我的问题是:如何在Spring Boot(1.3)应用程序中访问Hibernate Configuration类?默认情况下没有bean可以注入,也没有LocalSessionFactoryBean bean。

有人能指出我正确的方向,还是以其他方式注册我的SQL函数一次?

1 个答案:

答案 0 :(得分:2)

我更喜欢这个问题。

Hibernate使用org.hibernate.dialect.Dialect.SQLFunctionRegistry来识别数据库功能。

以下是hibernate核心4.3.10的示例。 在内部,它由两个私有字段组成:

/**
 * Defines a registry for SQLFunction instances
 *
 * @author Steve Ebersole
 */
public class SQLFunctionRegistry {
    private final Dialect dialect;
    private final Map<String, SQLFunction> userFunctions;

第一个字段代表数据库的方言。 第二个包含用户定义的函数,可以由org.hibernate.cfg.Configuration#addSqlFunction()填充。

不幸的是,在我通过hibernate源代码搜索时,我发现在初始化hibernate时创建的配置对象没有以任何方式暴露。

但是,我设法访问了SQLFunctionRegistry。

需要创建一个EntityManagerFactory

类型的本地自动装配字段
@Autowired
private EntityManagerFactory emFactory;

稍后调用以下代码:

private void registerMyDbFunctions()
{
    SQLFunctionRegistry registry = this.emFactory.unwrap(org.hibernate.internal.SessionFactoryImpl.class).getSqlFunctionRegistry();
    Field field = ReflectionUtils.findField(SQLFunctionRegistry.class, "userFunctions");
    ReflectionUtils.makeAccessible(field);
    Map<String, SQLFunction> userFunctions = (Map<String, SQLFunction>)ReflectionUtils.getField(field, registry);

    userFunctions.put("my_func", new SQLFunctionTemplate(TextType.INSTANCE, "my_func(?1, ?2)"));
}

由于userFunctions字段是私有字段而未在类中公开,因此我使用ReflectionUtils来获取其值。它通常是空的,我只是将它的数据库函数添加到它。

由于我必须进入SqlFunctionRegistry的内部,这是一个黑客,但我更喜欢它而不是创建新的数据库方言并弄乱它。