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

Tim*_*Tim 5 hibernate sql-function spring-data-jpa spring-boot

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

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

看着15.29.Hibernate文档中的非标准化函数,它说我应该使用org.hibernate.cfg.Configuration#addSqlFunction(),它似乎更便携,并且无需扩展所有三种方言.

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

任何人都可以指出我正确的方向,或以其他方式注册我的SQL函数一次?

小智 3

我对这个问题有一个破解方法。

Hibernate 用于org.hibernate.dialect.Dialect.SQLFunctionRegistry识别 DB 函数。

这是 hibernate core 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;
Run Code Online (Sandbox Code Playgroud)

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

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

但是,我设法访问 SQLFunctionRegistry。

需要创建一个 EntityManagerFactory 类型的本地自动装配字段

@Autowired
private EntityManagerFactory emFactory;
Run Code Online (Sandbox Code Playgroud)

然后调用以下代码:

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)"));
}
Run Code Online (Sandbox Code Playgroud)

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

因为我必须进入SqlFunctionRegistry的内部,所以这是一个 hack,但我更喜欢它而不是创建新的数据库方言并搞乱它。