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