SpringBoot多数据源(一)
- 1.多数据源使用场景
- 1.1 业务复杂(数据量大)
- 1.2 读写分离
- 2.多数据源配置
- 3.应用
- 4.测试
1.多数据源使用场景
1.1 业务复杂(数据量大)
简单理解就是业务量复杂,将庞大的数据拆到多个数据库中。或者由于公司有多个子项目,各用各的数据库,涉及数据共享
1.2 读写分离
为了解决数据库的读性能瓶颈(读比写性能更高,写锁会影响读阻塞,从而影响读的性能)。
与上述1.1不同的是,在读写分离中,主库和从库的数据库是一致的(不考虑主从延迟)。数据更新操作(insert
、update
、delete
)都是在主库上进行的,主库将数据更新信息同步给
从库。在查询时,可以在从库上进行。从而分担主库的压力。
2.多数据源配置
spring:
datasource:
#数据源1
datasource1:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test_master
username: root
password: root
druid:
initial-size: 1
min-idle: 1
max-active: 20
test-on-borrow: true
#数据源2
datasource2:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test_slave
username: root
password: root
druid:
initial-size: 1
min-idle: 1
max-active: 20
test-on-borrow: true
# mybatis的配置
mybatis:
type-aliases-package: com.rql.entity
mapper-locations: classpath:mybatis/*.xml
这里在配置时,特别注意在使用多配置源时,要将url
改为jdbc-url
。
对应两个数据库:
3.应用
下面是一个简单的SpringBoot整合mybatis的项目目录层级:
其中DataSourceConfig
用于定义DataSource Bean
,并通过@ConfigurationProperties
注解将配置文件中的属性映射到该Bean
的属性上
DataSourceConfig.java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource1")
public DataSource dataSource1(){
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.datasource2")
public DataSource dataSource2(){
return DataSourceBuilder.create().build();
}
}
上面只是创建了两个DataSource
的Bean
,分别为dataSource1
和dataSource2
,如果想要动态地根据操作去调用不同的数据源,那么就需要再创建一个Bean
,类似于代理的角色,根据条件来选择不同的数据源。
因此,创建DynamicDataSource.java
,并实现了DataSource
接口。
@Component
@Primary
public class DynamicDataSource implements DataSource, InitializingBean {
public static ThreadLocal<String> name=new ThreadLocal<>();
@Autowired
DataSource dataSource1;
@Autowired
DataSource dataSource2;
@Override
public Connection getConnection() throws SQLException {
if (name.get().equals("w")) {
return dataSource1.getConnection();
}
else {
return dataSource2.getConnection();
}
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
name.set("w");
}
}
这里主要通过getConnection()
方法来选择需要连接的数据源,因此根据读写操作的不同,设置一个值来区别(一般是使用枚举值,这样后面修改时不至于到代码中挨个去找),文中主要设置了一个参数,为了讲述方面。
public static ThreadLocal<String> name=new ThreadLocal<>();
注意到DynamicDataSource.java
也实现了InitializingBean
接口。
InitializingBean接口是Spring Framework中的一个重要接口,其主要目的是在Bean实例化后进行初始化操作。具体来说,当一个Bean实现了InitializingBean接口并被Spring容器创建后,Spring会在该Bean的属性设置完成后自动调用afterPropertiesSet()方法来执行一些额外的初始化逻辑。
因此,这里在Bean
实例化后,设置了name
的初始值。
4.测试
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserDao userDao;
@GetMapping("/a")
public List<User> selectUsers(){
DynamicDataSource.name.set("r");
return userDao.findAll();
}
@PostMapping("/b")
public void insertUser(@RequestBody User user){
DynamicDataSource.name.set("w");
userDao.inserUser(user);
}
}