英文:
How to dynamically set the JPA/Hibernate dialect when using AbstractRoutingDataSource with different database types?
问题
我在Spring Boot(Data JPA)应用程序中使用AbstractRoutingDataSource
来根据请求参数访问不同的数据库(Mariadb、SQL Server)。
此数据源(routingDatasource)被配置到LocalContainerEntityManagerFactoryBean
中。
问题在于,这种方法只能配置一个Hibernate方言,而应根据选择的数据源动态设置方言。为了实现这一目标,我尝试设置hibernate.dialect_resolvers
:
但是,此解析器只在第一次选择方言时被调用,因此所选方言将固定为它首次选择的方言。
是否有一种方法可以在运行时动态设置方言?
英文:
I'm using AbstractRoutingDataSource
in a Spring Boot (Data JPA) application to access different databases (Mariadb, SQL Server) depending of a request parameter.
public class DataSourceRouter extends AbstractRoutingDataSource {
public DataSourceRouter(Map<Object, Object> targetDataSources, DataSource defautDataSource) {
setTargetDataSources(targetDataSources);
setDefaultTargetDataSource(defautDataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return SelectedDataSourceContextHolder.getSelectedDataSource();
}
}
This datasource (routingDatasource) is configured into the LocalContainerEntityManagerFactoryBean
.
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
final EntityManagerFactoryBuilder builder) {
return buildEntityManagerFactory(builder, routingDatasource());
}
protected LocalContainerEntityManagerFactoryBean buildEntityManagerFactory(final EntityManagerFactoryBuilder builder, DataSource dataSource) {
return builder.dataSource(dataSource)
.packages(SomeEntity.class.getPackageName()).properties(
Map.of("hibernate.dialect_resolvers", "xxx.DynamicDialectResolver")
)
.build();
}
The problem with this approach is that we can only configure a single hibernate dialect, which should be dynamic depending on the underlying selected datasource. In order to do so I tried setting up a hibernate.dialect_resolvers
:
public class DynamicDialectResolver implements DialectResolver {
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
Dialect dialect;
switch (info.getDatabaseName()) {
case "MariaDB":
dialect = new org.hibernate.dialect.MySQL5Dialect();
break;
case "SQL Server":
dialect = new org.hibernate.dialect.SQLServer2012Dialect();
break;
default:
dialect = null;
break;
}
return dialect;
}
}
However this resolver is only invoked once, so the selected dialect with be fixed into the one it selects that first time.
Is there a way to set the dialect dynamically at runtime?
答案1
得分: 0
这是不可能的。Hibernate在引导时生成特定于方言的SQL,然后进行缓存。如果您需要支持多个数据库,您将需要多个会话工厂或持久化单元。
英文:
That's not possible. Hibernate generates SQL on bootstrap that is specific to the dialect which is then cached. If you need to support multiple databases, you will need multiple session factories or persistence units.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论