spring 在对不同的数据库类型使用AbstractRoutingDataSource时,如何动态设置JPA/Hibernate方言?

ncgqoxb0  于 2023-02-21  发布在  Spring
关注(0)|答案(1)|浏览(246)

我在Sping Boot (Data JPA)应用程序中使用AbstractRoutingDataSource,根据请求参数访问不同的数据库(Mariadb、SQL Server)。

public class DataSourceRouter extends AbstractRoutingDataSource {

    public DataSourceRouter(Map<Object, Object> targetDataSources, DataSource defautDataSource) {
        setTargetDataSources(targetDataSources);
        setDefaultTargetDataSource(defautDataSource);
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return SelectedDataSourceContextHolder.getSelectedDataSource();
    }

}

该数据源(routingDatasource)配置到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();
    }

这种方法的问题是我们只能配置一种Hibernate方言,它应该是动态的,取决于底层所选的数据源。

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;
    }
}

然而,这个解析器只被调用一次,所以所选的方言被固定为它第一次选择的方言。
有没有办法在运行时动态地设置方言?

pftdvrlh

pftdvrlh1#

这是不可能的。Hibernate在 Bootstrap 上生成特定于方言的SQL,然后缓存。如果需要支持多个数据库,则需要多个会话工厂或持久化单元。

相关问题