DataSource的种类
DataSource的基本角色是ConnectionFactory,所有的数据库连接将通过DataSource接口统一管理。
DataSource实现类根据功能强弱可以划分为以下三类:
简单的DataSource实现
org.springframework.jdbc.datasource.DriverManagerDataSource.
顾名思义,DriverManagerDataSource的提出,主要是为了替换最古老的基于java.sql.DriverManager获取连接的方式。
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://110.40.155.17:3306/test?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8",
"root","126433");
- DriverManagerDataSource的类结构继承图如下
- 通过IOC容器使用该DriverManagerDataSource的方法如下:
@Configuration
@Data
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceConfig {
private String url;
private String username;
private String password;
private String driverClassName;
@Bean
public DriverManagerDataSource driverManagerDataSource(){
DriverManagerDataSource source = new DriverManagerDataSource();
source.setUrl(url);
source.setDriverClassName(driverClassName);
source.setPassword(password);
source.setUsername(username);
return source;
}
}
org.springframework.jdbc.datasource.SingleConnectionDataSource
- 通过IOC容器使用该singleConnectionDataSource的方法如下:
@Bean
public SingleConnectionDataSource singleConnectionDataSource(){
SingleConnectionDataSource source = new SingleConnectionDataSource();
source.setUrl(url);
source.setDriverClassName(driverClassName);
source.setPassword(password);
source.setUsername(username);
source.setAutoCommit(true);
source.setSuppressClose(false);
return source;
}
拥有连接缓冲池的DataSource实现
常见的数据库连接池有cp30,driud等,这需要引入额外的依赖,这里不多进行演示。
对于这类DataSource,还需要额外指定连接池大小等参数。
支持分布式事务的DataSource
自定义DataSource
Spring提供了DelegatingDataSource的几个实现类
多数据源
主权独立的数据源
所谓主权独立是指系统中的每个数据源都对外独立承担公开数据库资源的职能:
该种数据源在spring中的简单使用如下:
public class Main {
public static void main(String[] args) {
DataSource mainDataSource = getMainDataSource();
JdbcTemplate main=new JdbcTemplate(mainDataSource);
DataSource otherDataSource = getOtherDataSource();
JdbcTemplate other = new JdbcTemplate(otherDataSource);
}
private static javax.sql.DataSource getMainDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
YamlUtil yamlUtil = new YamlUtil("application.yml");
basicDataSource.setDriverClassName(yamlUtil.get("spring.datasource.driver-class-name"));
basicDataSource.setUrl(yamlUtil.get("spring.datasource.url"));
basicDataSource.setUsername(yamlUtil.get("spring.datasource.username"));
basicDataSource.setPassword(yamlUtil.get("spring.datasource.password"));
return basicDataSource;
}
private static javax.sql.DataSource getOtherDataSource() {
...
return basicDataSource;
}
}
只需要不同的JdbcTemplate拥有不同的DataSource即可。
合作连横的多数据源
AbstractRoutingDataSource原理:
- getConnection方法会调用determineTargetDataSource来动态获得一个数据库连接
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
- determineTargetDataSource根据determineCurrentLookupKey返回值决定从dataSource集合中选择哪一个DataSource
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}
@Nullable
private Map<Object, Object> targetDataSources;
这里演示一下使用AbstractRoutingDataSource实现多数据源的管控:
@Data
public class DynamicDataSource extends AbstractRoutingDataSource {
private String datasource;
@Override
protected Object determineCurrentLookupKey() {
return datasource;
}
}
public class DataSourceTestHandler {
public static DataSource getHelperDataSource(){
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("xxx");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
return dataSource;
}
public static DataSource getTrainingDataSource(){
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("xxx");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
return dataSource;
}
public static DataSource getManagerDataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object,Object> sources=new HashMap<>();
sources.put("helper",getHelperDataSource());
sources.put("training",getTrainingDataSource());
dynamicDataSource.setTargetDataSources(sources);
return dynamicDataSource;
}
}
动态切换测试:
@ResponseBody
@GetMapping("/{dataSource}/{tableName}")
public AjaxResponse testMultiplyDataSource(@PathVariable(name = "dataSource") String dataSource,
@PathVariable(name = "tableName")String tableName) throws SQLException {
log.info("需要进行测试的数据源为: {}",dataSource);
return testService.testMultiplyDataSource(dataSource,tableName);
}
@Service
public class TestServiceImp implements TestService {
@Override
public AjaxResponse testMultiplyDataSource(String dataSource,String tableName) throws SQLException {
DynamicDataSource managerDataSource = (DynamicDataSource)getManagerDataSource();
managerDataSource.setDatasource(dataSource);
managerDataSource.afterPropertiesSet();
JdbcTemplate jdbcTemplate = new JdbcTemplate(managerDataSource);
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from " + tableName);
return AjaxResponse.success(list);
}
}
小结
合纵连横和主权独立可以联合使用:
可以用于存在多个数据源的场景,并且每个数据源存在多个实例,需要进行负载均衡
|