Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和 SQL 解析器组成。该项目主要是为了扩展 JDBC 的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计 SQL 信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,程序员可以通过定制来实现自己需要的功能。
Druid 首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个 ProxyDriver,一系列内置的 JDBC 组件库,一个 SQL Parser。在 Javad 的世界中 Druid 是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括 DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。
目前,业界流行的数据操作框架是 Mybatis,那 Druid 是什么呢?Druid 是 Java 的数据库连接池组件。Druid 能够提供强大的监控和扩展功能。比如可以监控 SQL ,在监控业务可以查询慢查询 SQL 列表等。
Druid 核心主要包括三部分:
DruidDriver 代理 Driver,能够提供基于 Filter-Chain 模式的插件体系。
DruidDataSource 高效可管理的数据库连接池
SQLParser 当业务数据量达到了一定程度,DBA 需要合理配置数据库资源。即配置主库的机器-高配置,把核心高频的数据放在主库上;把次要的数据放在从库-低配置。开源节流嘛,就这个意思。把数据放在不同的数据库里,就需要通过不同的数据源进行操作数据。
实例:user 用户表在主库 master 上,地址表 city 在从库 cluster 上。下面实现获取,根据用户名获取用户信息,包括从库的地址信息,那么需要从主库和从库中分别获取数据,并在业务逻辑层组装返回。
主表
DROP TABLE IF EXISTS `user`;
CREATE TABLE user
(
id INT(10) unsigned PRIMARY KEY NOT NULL COMMENT '用户编号' AUTO_INCREMENT,
user_name VARCHAR(25) COMMENT '用户名称',
description VARCHAR(25) COMMENT '描述'
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入数据
INSERT user VALUES (1 ,'博闻','微信公众号【猿码天地】');
从表
DROP TABLE IF EXISTS `city`;
CREATE TABLE `city` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '城市编号',
`province_id` int(10) unsigned NOT NULL COMMENT '省份编号',
`city_name` varchar(25) DEFAULT NULL COMMENT '城市名称',
`description` varchar(25) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入数据
INSERT city VALUES (1 ,1001,'深圳市','猿码天地');
com.bowen.config - 配置层(数据源配置)
com.bowen.controller - Controller层
com.bowen.dao - 数据操作层DAO
com.bowen.domain - 实体类
com.bowen..service - 业务逻辑层
SrpingbootDruidApplication - 应用启动类
application.properties - 应用配置文件,应用启动会自动读取配置。
需要引入Spring Boot Mybatis 依赖、MySQL 连接驱动依赖、Druid 数据连接池依赖等。
4.0.0
com.bowen
srpingboot-druid
0.0.1-SNAPSHOT
jar
srpingboot-druid
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.3.1.RELEASE
UTF-8
UTF-8
1.8
1.2.0
5.1.39
1.0.18
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis-spring-boot}
mysql
mysql-connector-java
${mysql-connector}
com.alibaba
druid
${druid}
junit
junit
4.12
org.springframework.boot
spring-boot-starter-test
test
分别配置了master 数据源和cluster 数据源。
## master 数据源配置
master.datasource.url=jdbc:mysql://localhost:3306/db_druid1?useUnicode=true&characterEncoding=utf8
master.datasource.username=root
master.datasource.password=123456
master.datasource.driverClassName=com.mysql.jdbc.Driver
## cluster 数据源配置
cluster.datasource.url=jdbc:mysql://localhost:3306/db_druid2?useUnicode=true&characterEncoding=utf8
cluster.datasource.username=root
cluster.datasource.password=123456
cluster.datasource.driverClassName=com.mysql.jdbc.Driver
多数据源配置的时候,必须要有一个主数据源,即 MasterDataSourceConfig 配置:
package com.bowen.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
// 扫描 Mapper 接口并容器管理
@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
// 精确到 master 目录,以便跟其他数据源隔离
static final String PACKAGE = "com.bowen.dao.master";
static final String MAPPER_LOCATION = "classpath:mapper/master/*.xml";
@Value("${master.datasource.url}")
private String url;
@Value("${master.datasource.username}")
private String user;
@Value("${master.datasource.password}")
private String password;
@Value("${master.datasource.driverClassName}")
private String driverClass;
@Bean(name = "masterDataSource")
@Primary
public DataSource masterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
return dataSource;
}
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource());
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(masterDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(MasterDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
@Primary 标志这个 Bean 如果在多个同类 Bean 候选时,该 Bean 优先被考虑。「多数据源配置的时候注意,必须要有一个主数据源,用 @Primary 标志该 Bean」
@MapperScan 扫描 Mapper 接口并给容器管理,包路径精确到 master,为了和下面 cluster 数据源做到精确区分。
@Value 获取全局配置文件 application.properties 的 kv 配置,并自动装配。
sqlSessionFactoryRef 表示定义了 key ,表示一个唯一 SqlSessionFactory 实例。
从数据源 ClusterDataSourceConfig 配置如下:
package com.bowen.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
// 扫描 Mapper 接口并容器管理
@MapperScan(basePackages = ClusterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "clusterSqlSessionFactory")
public class ClusterDataSourceConfig {
// 精确到 cluster 目录,以便跟其他数据源隔离
static final String PACKAGE = "com.bowen.dao.cluster";
static final String MAPPER_LOCATION = "classpath:mapper/cluster/*.xml";
@Value("${cluster.datasource.url}")
private String url;
@Value("${cluster.datasource.username}")
private String user;
@Value("${cluster.datasource.password}")
private String password;
@Value("${cluster.datasource.driverClassName}")
private String driverClass;
@Bean(name = "clusterDataSource")
public DataSource clusterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
return dataSource;
}
@Bean(name = "clusterTransactionManager")
public DataSourceTransactionManager clusterTransactionManager() {
return new DataSourceTransactionManager(clusterDataSource());
}
@Bean(name = "clusterSqlSessionFactory")
public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("clusterDataSource") DataSource clusterDataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(clusterDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(ClusterDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
上面数据配置分别扫描 Mapper 接口,com.bowen.dao.master(对应 xml classpath:mapper/master ) 和 com.bowen.dao.cluster(对应 xml classpath:mapper/cluster ) 包中对应的 UserDAO 和 CityDAO 。都有 @Mapper 标志为 Mybatis 的并通过容器管理的 Bean。Mybatis 内部会使用反射机制运行去解析相应 SQL。
业务层 biz 注入了两个 DAO,不用关心和指定到具体说明数据源。
package com.bowen.service.impl;
import com.bowen.dao.cluster.CityDao;
import com.bowen.dao.master.UserDao;
import com.bowen.domain.City;
import com.bowen.domain.User;
import com.bowen.service.UserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 用户业务实现层
*/
@Service
public class UserServiceImpl implements UserService {
/**
* 主数据源
*/
@Resource
private UserDao userDao;
/**
* 从数据源
*/
@Resource
private CityDao cityDao;
@Override
public User findByName(String userName) {
User user = userDao.findByName(userName);
City city = cityDao.findByName("深圳市");
user.setCity(city);
return user;
}
}
启动工程,浏览器输入:http://localhost:8091/test/api/user?userName=博闻
结果:
这里 city 结果体来自 cluster 库,user 结果体来自 master 库,达到了多数据源配置获取数据的目的。
Druid 是一款非常优秀的数据库连接池开源软件,使用 Druid 提供的druid-spring-boot-starter可以非常简单的对 Druid 进行集成。
Druid 提供了很多预置的功能,非常方便对 SQL 进行监控、分析。在集成多数据源的时候,我们配置不同数据源,采用一层一层注入的形式,最终构建出对应的SqlSessionTemplate,并将其注入到对应的 Mapper 包中来使用。
利用 Druid 属性继承的功能,可以简化多数据源的配置,MyBatis+Druid 的多数据源解决方案很简单高效。
多数据源适合的场景很多。不同的 DataSource ,不同的 SqlSessionFactory 和 不同的 DAO 层,在业务逻辑层做整合。总体的架构图如下:
源码下载地址:关注公众号【猿码天地】并回复 springboot 获取
文章推荐
Java泛型详解,必须掌握
第004课:Spring Boot 项目属性配置
第005课:Spring Boot 中MVC支持
第003课:Spring Boot 快速体验 Web 开发
Maven 的这 7 个问题你思考过没有?
你可以不尊重我的人,但必须尊重我的代码...
第001课:Spring Boot 课程概览
第002课:Spring Boot 开发环境搭建
50份Java优秀求职者简历
你多学一样本事,就少说一句求人的话,现在的努力,是为了以后的不求别人,实力是最强的底气。记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。
——《写给程序员朋友》