Spring中的DataSource

Spring中的DataSource

Spring中的DataSourceDataSource的种类简单的DataSource实现拥有连接缓冲池的DataSource实现支持分布式事务的DataSource自定义DataSource多数主权独立的数据源合作连横的多数据源小结DataSource的种类DataSource的基本角色是ConnectionFactory,所有的数据库连接将通过DataSource接口统一管理。

DataSource实现类根据功能强弱可以划分为以下三类:

简单的DataSource实现 org.springframework.jdbc.datasource.DriverManagerDataSource.

顾名思义,DriverManagerDataSource的提出,主要是为了替换最古老的基于java.sql.DriverManager获取连接的方式。

代码语言:javascript复制 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的方法如下:代码语言:javascript复制@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的方法如下:代码语言:javascript复制 @Bean

public SingleConnectionDataSource singleConnectionDataSource(){

SingleConnectionDataSource source = new SingleConnectionDataSource();

source.setUrl(url);

source.setDriverClassName(driverClassName);

source.setPassword(password);

source.setUsername(username);

//可以设置是否开启自动提交---默认为true

source.setAutoCommit(true);

//close方法调用,也不会关闭连接

source.setSuppressClose(false);

return source;

}拥有连接缓冲池的DataSource实现

常见的数据库连接池有cp30,driud等,这需要引入额外的依赖,这里不多进行演示。

对于这类DataSource,还需要额外指定连接池大小等参数。

支持分布式事务的DataSource自定义DataSourceSpring提供了DelegatingDataSource的几个实现类

多数据源主权独立的数据源所谓主权独立是指系统中的每个数据源都对外独立承担公开数据库资源的职能:

该种数据源在spring中的简单使用如下:

代码语言:javascript复制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来动态获得一个数据库连接代码语言:javascript复制 @Override

public Connection getConnection() throws SQLException {

return determineTargetDataSource().getConnection();

}determineTargetDataSource根据determineCurrentLookupKey返回值决定从dataSource集合中选择哪一个DataSource代码语言:javascript复制 protected DataSource determineTargetDataSource() {

Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");

//determineCurrentLookupKey抽象方法,负责返回指定的key,然后去集合中动态获取到目标的dataSource

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;

}存储dataSource的map集合代码语言:javascript复制 @Nullable

private Map targetDataSources;这里演示一下使用AbstractRoutingDataSource实现多数据源的管控:

代码语言:javascript复制@Data

public class DynamicDataSource extends AbstractRoutingDataSource {

private String datasource;

@Override

protected Object determineCurrentLookupKey() {

return datasource;

}

}代码语言:javascript复制public class DataSourceTestHandler {

/**

* 获得helper数据库的数据源

*/

public static DataSource getHelperDataSource(){

HikariDataSource dataSource = new HikariDataSource();

dataSource.setJdbcUrl("xxx");

dataSource.setUsername("xxx");

dataSource.setPassword("xxx");

return dataSource;

}

/**

* 获得training数据库的数据源

*/

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 sources=new HashMap<>();

sources.put("helper",getHelperDataSource());

sources.put("training",getTrainingDataSource());

dynamicDataSource.setTargetDataSources(sources);

return dynamicDataSource;

}

}动态切换测试:

代码语言:javascript复制 /**

* 多数据源结果测试

*/

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

}代码语言:javascript复制@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> list = jdbcTemplate.queryForList("select * from " + tableName);

return AjaxResponse.success(list);

}

}小结合纵连横和主权独立可以联合使用:

合纵连横争取主权独立 可以用于存在多个数据源的场景,并且每个数据源存在多个实例,需要进行负载均衡

主权独立并入合纵连横