Spring Boot多数据源配置


@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix="spring.datasource.uc") // 使用不同配置前缀区分
    public DataSourceProperties ucDataSourceProperties(){
        return new DataSourceProperties();
    }

    @Bean(name = "ucDataSource")
    public DataSource ucDataSource(@Qualifier("ucDataSourceProperties") DataSourceProperties ucDataSourceProperties) {
        return ucDataSourceProperties.initializeDataSourceBuilder().build();
    }

    @Bean
    @Primary
    @ConfigurationProperties(prefix="spring.datasource.mc") // 使用不同配置前缀区分
    public DataSourceProperties mcDataSourceProperties(){
        return new DataSourceProperties();
    }

    @Bean(name = "mcDataSource")
    @Primary // 默认数据源
    public DataSource mcDataSource(DataSourceProperties mcDataSourceProperties) {
        return mcDataSourceProperties.initializeDataSourceBuilder().build();
    }
}

mc是主数据库,是mysql数据库。uc是从数据库,是oracle数据库。

在uc相关的FansRepository执行分页查询时,发现hibernate生成的sql语句分页使用的是limit,也就是说 uc数据库使用的dialect是mysql的。

猜测dialect是spring根据主数据库类型推断出来的。如果FansRepository要使用oracle的dialect需要另外配置。 代码中通过JpaConfig配置Oracle相关参数,代码如下:

private Map<String, String> getVendorProperties(DataSource dataSource) {
    return jpaProperties.getHibernateProperties(dataSource);
}

可在此处为uc数据库指定dialect。

最简单的方式,代码改为如下:

private static final String HIBERNATE_DIALECT = "hibernate.dialect";

@Value("${uc.hibernate.dialect}")
private String hibernateDialect;

private Map<String, String> getVendorProperties(DataSource dataSource) {
    Map<String, String> properties = jpaProperties.getHibernateProperties(dataSource);      properties.put(HIBERNATE_DIALECT, hibernateDialect);
    return properties;
}

在配置文件中增加配置项:

uc.hibernate.dialect=org.hibernate.dialect.OracleDialect

问题解决。

但是这样写感觉有点死,如果再加一个配置项,就得重复上面的工作。数据库配置可以用DataSourceProperties类统一 接收,jpa配置也有对应的JpaProperties,那我能不能像DataSourceProperties一样为uc配一个专门的JpaProperties?

查看JpaProperties源代码发现,JpaProperties有一个map类型的properties属性,这个属性用来接收一些本地配置, 可以利用这个属性做些事情。

首先增加如下配置:

spring.jpa.uc.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect

DataSourceConfig中配置一个uc专用的JpaProperties:

@Bean(name = "ucJpaProperties")
@ConfigurationProperties(prefix="spring.jpa.uc") // 使用不同配置前缀区分, 接收uc专用jpa配置
public JpaProperties ucJpaProperties(){
    return new JpaProperties();
}

在UcJpaConfig中,做如下修改:

@Autowired
@Qualifier("ucJpaProperties")
private JpaProperties ucJpaProperties;

private Map<String, String> getVendorProperties(DataSource dataSource) {
    Map<String, String> properties = jpaProperties.getHibernateProperties(dataSource);
    properties.putAll(ucJpaProperties); // 将uc专用的jpa配置放入properties中
    return properties;
}

启动项目,报错,说JpaProperties无法正常注入,需要用Qualifier指定一下。配置UCJpaProperties之前,代码能正常 运行,说明spring本身会生成一个JpaProperties。用Qualifier指定一下:

@Autowired
@Qualifier("jpaProperties")
private JpaProperties jpaProperties;

启动还是报错,说找不到名为jpaProperties的bean。使用9001查看spring的bean,发现自动生成的JpaProperties名称为 spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties

将代码改成:

@Autowired
@Qualifier("spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties")
private JpaProperties jpaProperties;

可以正常启动。

名称太长,可以在DataSourceConfig中增加个额外配置:

@Autowired
@Qualifier("spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties")
private JpaProperties jpaProperties;

@Bean(name = "jpaProperties")
public JpaProperties jpaPropertiesXXX(){
    return jpaProperties;
}

这样在UcJpaConfig和McJpaConfig中就可以使用jpaProperties的名字了。

接下来在增加别的配置项,只要改配置文件就可以了。

还有第三种方式也可以达到这种效果。

直接使用Map来接收参数,这样就不用为uc配置专门的UCJpaProperties,也就不用去改JpaProperties的配置了。

@Bean(name = "ucJpaProperties")
@ConfigurationProperties(prefix="spring.jpa.uc.properties") // 使用不同配置前缀区分
public Map<String, String> ucJpaProperties(){
    return new HashMap<String, String>();
}

配置项改为:

spring.jpa.uc.properties[hibernate.dialect]=org.hibernate.dialect.Oracle10gDialect

一定要用中括号。如果用".",key会被spring解析成嵌套的map。

UcJpaConfig配置:

@Autowired
private JpaProperties jpaProperties;

@Autowired
@Qualifier("ucJpaProperties")
private Map<String,String> ucJpaProperties;

results matching ""

    No results matching ""