目前,業界流行的數據操作框架是 Mybatis,那 Druid 是什么呢? Druid 是 Java 的數據庫連接池組件。Druid 能夠提供強大的監控和擴展功能。比如可以監控 SQL ,在監控業務可以查詢慢查詢 SQL 列表等。Druid 核心主要包括三部分: 1. DruidDriver 代理 Driver,能夠提供基於 Filter-Chain 模式的插件體系。 2. DruidDataSource 高效可管理的數據庫連接池 3. SQLParser 當業務數據量達到了一定程度,DBA 需要合理配置數據庫資源。即配置主庫的機器高配置,把核心高頻的數據放在主庫上;把次要的數據放在低配置的從庫。開源節流嘛,把數據放在不同的數據庫里,就需要通過不同的數據源進行操作數據。這里我們舉個 springboot-mutil-datasource 工程案例: user 用戶表在主庫 master 上,地址表 city 在從庫 slave上。
一、數據庫准備
1、主庫master
CREATE DATABASE master; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用戶編號', `user_name` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶名稱', `description` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT user VALUES (1 ,'程序員','他有一個小網站 tom.com.cn');
2、從庫slave
CREATE DATABASE slave; 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) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '城市名稱', `description` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT city VALUES (1 ,1,'北京市','tom的家在北京。');
二、工程代碼配置詳解
com.carry.springboot.config.ds 包下包含了多數據源的配置,同樣可以有第三個數據源,按照前幾個復制即可 resources/mapper 下面有兩個模塊,分別是 Mybatis 不同數據源需要掃描的 mapper xml 目錄
2、pom.xml依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.carry.elk</groupId> <artifactId>springboot-mutil-datasource</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-mutil-datasource</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <druid>1.0.31</druid> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- Druid 數據連接池依賴 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3、application.properties 配置兩個數據源配置
## master 數據源配置 master.datasource.url=jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=utf8 master.datasource.username=root master.datasource.password=123456 master.datasource.driverClassName=com.mysql.jdbc.Driver ## slave 數據源配置 slave.datasource.url=jdbc:mysql://localhost:3306/slave?useUnicode=true&characterEncoding=utf8 slave.datasource.username=root slave.datasource.password=123456 slave.datasource.driverClassName=com.mysql.jdbc.Driver #熱部署 spring.devtools.restart.enabled=true
4、主數據源MasterDataSourceConfig 配置
package com.carry.springboot.config.ds; import javax.sql.DataSource; 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 com.alibaba.druid.pool.DruidDataSource; @Configuration // 掃描 Mapper 接口並容器管理 @MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterDataSourceConfig { // 精確到 master 目錄,以便跟其他數據源隔離 static final String PACKAGE = "com.carry.springboot.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(); } }
5、從數據源SlaveDataSourceConfig配置
package com.carry.springboot.config.ds; import javax.sql.DataSource; 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 com.alibaba.druid.pool.DruidDataSource; @Configuration // 掃描 Mapper 接口並容器管理 @MapperScan(basePackages = SlaveDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "slaveSqlSessionFactory") public class SlaveDataSourceConfig { // 精確到 slave 目錄,以便跟其他數據源隔離 static final String PACKAGE = "com.carry.springboot.dao.slave"; static final String MAPPER_LOCATION = "classpath:mapper/slave/*.xml"; @Value("${slave.datasource.url}") private String url; @Value("${slave.datasource.username}") private String user; @Value("${slave.datasource.password}") private String password; @Value("${slave.datasource.driverClassName}") private String driverClass; @Bean(name = "slaveDataSource") public DataSource slaveDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driverClass); dataSource.setUrl(url); dataSource.setUsername(user); dataSource.setPassword(password); return dataSource; } @Bean(name = "slaveTransactionManager") public DataSourceTransactionManager slaveTransactionManager() { return new DataSourceTransactionManager(slaveDataSource()); } @Bean(name = "slaveSqlSessionFactory") public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(slaveDataSource); sessionFactory.setMapperLocations( new PathMatchingResourcePatternResolver().getResources(SlaveDataSourceConfig.MAPPER_LOCATION)); return sessionFactory.getObject(); } }
6、業務層代碼
package com.carry.springboot.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.carry.springboot.dao.master.UserDao; import com.carry.springboot.dao.slave.CityDao; import com.carry.springboot.domain.City; import com.carry.springboot.domain.User; import com.carry.springboot.service.UserService; @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; // 主數據源 @Autowired private CityDao cityDao; // 從數據源 @Override public User findByName(String userName) { User user = userDao.findByName(userName); City city = cityDao.findByName("北京市"); user.setCity(city); return user; } }
三、測試
寫個controller和request方法,我這里的是http://localhost:8080/api/user