如何让 AbstractRoutingDataSource 正常工作?

Posted

技术标签:

【中文标题】如何让 AbstractRoutingDataSource 正常工作?【英文标题】:How do I get AbstractRoutingDataSource to work properly? 【发布时间】:2016-08-27 05:29:25 【问题描述】:

我目前正在尝试在使用 AbstractRoutingDataSource 时创建 Hibernate 会话工厂,但是当它通过 bean 初始化过程时,它会尝试确定查找键。因为我没有设置默认值,所以它将为空。我不想设置默认值 - 我宁愿延迟它,直到我需要创建会话并进行实际查询。

我确实发现其他人也有同样的问题。这是 2005 年的旧存档帖子,描述了我遇到的完全相同的问题。不幸的是,没有真正的答案:

http://forum.spring.io/forum/spring-projects/data/108464-abstractroutingdatasource-not-routing-when-used-with-hibernate-sample-attached

如果我设置一个默认值,一切都会加载“正常” - 但随后更改路由数据源所依赖的线程本地值对使用的数据库的影响为零 - 在那一点上似乎“锁定”了。

有什么想法吗?

【问题讨论】:

您后来解决了这个问题吗?如果是,请分享您的解决方案。 【参考方案1】:

AbstractRoutingDataSource 继承数据源。因此它可能会替换必须在启动时配置的数据源。

您可以将数据源列表加载到DataSourceProperties 组件:

@Component
@ConfigurationProperties(prefix = "tenants")
public class DataSourceProperties 

    private Map <Object, Object> datasources = new LinkedHashMap <>();

    public Map<Object, Object> getDatasources() 
        return datasources;
    

    public void setDatasources(Map<String, Map<String, String>> datasources) 
        datasources
                .forEach((key, value) -> this.datasources.put(key, convert(value)));
    

    private DataSource convert(Map <String, String> source) 
        return DataSourceBuilder.create()
                .url(source.get("jdbcUrl"))
                .driverClassName(source.get("driverClassName"))
                .username(source.get("username"))
                .password(source.get("password"))
                .build();
    

创建AbstractRoutingDataSource:

public class TenantAwareRoutingDataSource extends AbstractRoutingDataSource 

    @Override
    protected Object determineCurrentLookupKey() 
        return ThreadLocalStorage.getTenantName();
    

并将您的数据源配置为AbstractRoutingDataSource

@Configuration
public class DataSourceConfig 

    private final DataSourceProperties dataSourceProperties;

    public DataSourceConfig(DataSourceProperties dataSourceProperties) 
        this.dataSourceProperties = dataSourceProperties;
    

    @Bean
    public DataSource getDataSource() 
        TenantAwareRoutingDataSource tenantAwareRoutingDataSource = new TenantAwareRoutingDataSource();
        tenantAwareRoutingDataSource.setTargetDataSources(dataSourceProperties.getDatasources());
        tenantAwareRoutingDataSource.afterPropertiesSet();
        return tenantAwareRoutingDataSource;
    

您还应该实现ThreadLocalStorage 来存储租户标识符并让 AbstractRoutingDataSource 检索它以确定要使用的数据源。

为了防止 Spring 在启动时自动配置数据源:

spring:
  jpa:
    open-in-view: false        # Get Rid of OIV Warning
    show-sql: true
    database: postgresql       # Do not Auto-Detect the Database
    hibernate: 
      ddl-auto: none           # Prevent Hibernate from Automatic Changes to the DDL Schema
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
  datasource:
    initialization-mode: never  # Prevent JPA from trying to Initialize

【讨论】:

以上是关于如何让 AbstractRoutingDataSource 正常工作?的主要内容,如果未能解决你的问题,请参考以下文章

Jfreechart柱状图如何让变成纯色

android中如何让文字环绕图片

如何让GridView 标题居中

请教如何让UIActivityIndicatorView永远居中

如何让ActionBar标题居中

EBS如何让从值集不显示