我的应用程序需要在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函数一次?
答案 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
的内部,这是一个黑客,但我更喜欢它而不是创建新的数据库方言并弄乱它。