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

问题描述 投票:5回答:1

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

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

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

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

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

hibernate spring-boot spring-data-jpa sql-function
1个回答
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的内部,这是一个黑客,但我更喜欢它创建新的数据库方言并弄乱它。

© www.soinside.com 2019 - 2024. All rights reserved.