How to dynamically set the JPA/Hibernate dialect when using AbstractRoutingDataSource with different database types?

huangapple go评论63阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年2月14日 20:23:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75447783.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定