核心技术点介绍
1.springBoot项目
2.mybatis
3.Druid连接池
创建测试表
1.创建两个 数据库 db_test1,与 db_test2
2.分别在两个库-创建测试表
CREATE TABLE `user_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键id',
`user_id` varchar(32) NOT NULL COMMENT '人员id',
`user_name` varchar(32) NOT NULL COMMENT '用户名',
`user_password` varchar(32) NOT NULL COMMENT '密码',
`real_name` varchar(64) NOT NULL COMMENT '真实姓名',
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记 0正常 1-删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniq_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='人员信息表';
3.插入测试数据
3.1 DB1 模拟数据
INSERT INTO `db_test1`.`user_info`(`id`, `user_id`, `user_name`, `user_password`, `real_name`, `mobile`, `remark`, `create_time`, `update_time`, `del_flag`) VALUES (1, '1001', 'zhangsan', '123456', '张三', '13235717777', '我是DB1 - 张三', now(), now(), 0);
3.2 DB2 模拟数据
INSERT INTO `db_test2`.`user_info`(`id`, `user_id`, `user_name`, `user_password`, `real_name`, `mobile`, `remark`, `create_time`, `update_time`, `del_flag`) VALUES (1, '1001', 'lisi', '333222', '李四', '15678298934', '我是DB2 - 李四', now(), now(), 0);
INSERT INTO `db_test2`.`user_info`(`id`, `user_id`, `user_name`, `user_password`, `real_name`, `mobile`, `remark`, `create_time`, `update_time`, `del_flag`) VALUES (2, '1002', 'wangwu', '555666', '王五', '18778298934', '我是DB2 - 王五', now(), now(), 0);
Maven依赖
<?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.example</groupId>
<artifactId>spring-boot-mybatis-many-datasource</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-boot-mybatis-many-datasource</name>
<description>Demo project for Spring Boot and mybatis many datasource</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.14.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<alibaba.druid.version>1.0.29</alibaba.druid.version>
<mysql-connector.version>5.1.41</mysql-connector.version>
<mybatis-spring-boot.version>1.3.1</mybatis-spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 依赖 -->
<dependencies>
<!-- spring-boot 相关 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mysql connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
</dependency>
<!-- druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${alibaba.druid.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
添加配置文件
server.port=8081
#数据源 >> 1 >> 配置
#连接地址
spring.datasource.test1.url=jdbc:mysql://localhost:3306/db_test1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC&useSSL=false
#用户名
spring.datasource.test1.username=root
#密码
spring.datasource.test1.password=root
#驱动
spring.datasource.test1.driver-class-name=com.mysql.jdbc.Driver
#连接池其它设置
#初始化时建立物理连接的个数
spring.datasource.test1.initial-size=5
#最小连接池数量
spring.datasource.test1.min-idle=5
#最大连接池数量 maxIdle已经不再使用
spring.datasource.test1.max-active=20
#获取连接时最大等待时间,单位毫秒
spring.datasource.test1.max-wait=60000
#申请连接检测,空闲时间大于检测的间隔时间,执行validationQuery检测
spring.datasource.test1.test-while-idle=true
#检测的间隔时间
spring.datasource.test1.time-between-eviction-runs-millis=60000
#销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
spring.datasource.test1.min-evictable-idle-time-millis=30000
#用来检测连接是否有效
spring.datasource.test1.validation-query=SELECT 1 FROM DUAL
#申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
spring.datasource.test1.test-on-borrow=false
#归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
spring.datasource.test1.test-on-return=false
#数据源 >> 2 >> 配置
#连接地址
spring.datasource.test2.url=jdbc:mysql://localhost:3306/db_test2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC&useSSL=false
#用户名
spring.datasource.test2.username=root
#密码
spring.datasource.test2.password=root
#驱动
spring.datasource.test2.driver-class-name=com.mysql.jdbc.Driver
#连接池其它设置
#初始化时建立物理连接的个数
spring.datasource.test2.initial-size=5
#最小连接池数量
spring.datasource.test2.min-idle=5
#最大连接池数量 maxIdle已经不再使用
spring.datasource.test2.max-active=20
#获取连接时最大等待时间,单位毫秒
spring.datasource.test2.max-wait=60000
#申请连接检测,空闲时间大于检测的间隔时间,执行validationQuery检测
spring.datasource.test2.test-while-idle=true
#检测的间隔时间
spring.datasource.test2.time-between-eviction-runs-millis=60000
#销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
spring.datasource.test2.min-evictable-idle-time-millis=30000
#用来检测连接是否有效
spring.datasource.test2.validation-query=SELECT 1 FROM DUAL
#申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
spring.datasource.test2.test-on-borrow=false
#归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
spring.datasource.test2.test-on-return=false
#日志配置
logging.level.root=WARN
logging.level.com.example=debug
启动类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
/**
* 启动类
*
* @author 码农猿
* @date 2019-03-25
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
数据源常量
注意: mapper xml文件地址 要写全路径
package com.example.config.constant;
/**
* 数据源常量
*
* @author 码农猿
* @date 2019-03-25
*/
public class DataSourceConstant {
//************** 数据源1 配置 **************
/**
* mapper 接口包地址
*/
public static final String DB1_BASE_PACKAGES = "com.example.mapper.db1";
/**
* 数据源配置 前缀
*/
public static final String DB1_DATA_SOURCE_PREFIX = "spring.datasource.test1";
/**
* mapper xml文件地址
*/
public static final String DB1_MAPPER_LOCATION = "classpath:mybatis/mapper/db1/*.xml";
//************** 数据源 2 配置 **************
/**
* mapper 接口包地址
*/
public static final String DB2_BASE_PACKAGES = "com.example.mapper.db2";
/**
* 数据源配置 前缀
*/
public static final String DB2_DATA_SOURCE_PREFIX = "spring.datasource.test2";
/**
* mapper xml文件地址
*/
public static final String DB2_MAPPER_LOCATION = "classpath:mybatis/mapper/db2/*.xml";
}
数据源配置
DB1-数据源2 配置
注意:主数据源,添加注解@Primary:在众多相同的bean中,优先选择用@Primary注解的bean(该注解加在各个bean上)
package com.example.config.datasource;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.config.constant.DataSourceConstant;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;
/**
* 数据源1 > 配置
*
* @author 码农猿
* @date 2019-03-25
* 说明一下两个注解的作用
* -- @Primary:在众多相同的bean中,优先选择用@Primary注解的bean(该注解加在各个bean上)
* -- @Qualifier:在众多相同的bean中,@Qualifier指定需要注入的bean(该注解跟随在@Autowired后)
*/
@Configuration
@MapperScan(basePackages = DataSourceConstant.DB1_BASE_PACKAGES, sqlSessionTemplateRef = "test1SqlSessionTemplate")
public class DataSource1Config {
/**
* 数据源配置
* 使用的连接池是 DruidDataSource
* <p>
* 注解ConfigurationProperties
* 作用就是将全局配置文件中的属性值注入到DruidDataSource 的同名参数
*/
@Primary
@Bean(name = "test1DataSource")
@Qualifier("test1DataSource")
@ConfigurationProperties(prefix = DataSourceConstant.DB1_DATA_SOURCE_PREFIX)
public DataSource testDataSource() {
//DataSourceBuilder.create().build() 默认数据源类型是 org.apache.tomcat.jdbc.pool.DataSource
//这里指定使用类型 -- 阿里DruidDataSource 连接池
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}
/**
* 创建 SqlSessionFactory 工厂
*/
@Primary
@Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(DataSourceConstant.DB1_MAPPER_LOCATION));
return bean.getObject();
}
/**
* 事务管理
*/
@Primary
@Bean(name = "test1TransactionManager")
public DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* MyBatis提供的持久层访问模板化的工具
* 线程安全,可通过构造参数或依赖注入SqlSessionFactory实例
*/
@Primary
@Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
DB2-数据源2 配置
package com.example.config.datasource;
import com.alibaba.druid.pool.DruidDataSource;
import com.example.config.constant.DataSourceConstant;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;
/**
* 数据源2 > 配置
*
* @author 码农猿
* @date 2019-03-25
* 说明一下两个注解的作用
* -- @Primary:在众多相同的bean中,优先选择用@Primary注解的bean(该注解加在各个bean上)
* -- @Qualifier:在众多相同的bean中,@Qualifier指定需要注入的bean(该注解跟随在@Autowired后)
*/
@Configuration
@MapperScan(basePackages = DataSourceConstant.DB2_BASE_PACKAGES, sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class DataSource2Config {
/**
* 数据源配置
* 使用的连接池是 DruidDataSource
* <p>
* 注解ConfigurationProperties
* 作用就是将全局配置文件中的属性值注入到DruidDataSource 的同名参数
*/
@Bean(name = "test2DataSource")
@ConfigurationProperties(prefix = DataSourceConstant.DB2_DATA_SOURCE_PREFIX)
public DataSource testDataSource() {
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}
/**
* 创建 SqlSessionFactory 工厂
*/
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
//数据源
bean.setDataSource(dataSource);
//mapper 地址
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(DataSourceConstant.DB2_MAPPER_LOCATION));
return bean.getObject();
}
/**
* 事务管理
*/
@Bean(name = "test2TransactionManager")
public DataSourceTransactionManager testTransactionManager(@Qualifier("test2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* MyBatis提供的持久层访问模板化的工具
* 线程安全,可通过构造参数或依赖注入SqlSessionFactory实例。
*/
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
人员信息实体Bean
package com.example.entity;
import java.io.Serializable;
import java.util.Date;
/**
* 人员信息实体类
*
* @author 码农猿
* @date 2019-03-25 23:08:13
*/
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 自增主键id
*/
private Integer id;
/**
* 人员id
*/
private String userId;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String userPassword;
/**
* 真实姓名
*/
private String realName;
/**
* 手机号
*/
private String mobile;
/**
* 创建时间
*/
private Date createTime;
/**
* 修改时间
*/
private Date updateTime;
/**
* 删除标记
*/
private Integer delFlag;
/**
* remark
*/
private String remark;
//省略 get,set 方法
}
Mapper 文件
DB1-测试Mapper 1
package com.example.mapper.db1;
import com.example.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 测试 数据源 1 - mapper1
* <p>
* 人员信息mapper接口
*
* @author 码农猿
* @date 2019-03-25 23:08:13
*/
public interface UserInfo1Mapper {
/**
* 查询所有 人员信息
*
* @return 人员信息 列表
* @author 码农猿
* @date 2019-03-25 23:08:13
*/
List<UserInfo> listAll();
/**
* 根据业务主键id查询
*
* @param userId 业务主键
* @return 人员信息实体
* @author 码农猿
* @date 2019-03-25 23:08:13
*/
UserInfo getByUserId(String userId);
}
DB2-测试Mapper 2
package com.example.mapper.db2;
import com.example.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 测试 数据源 2 - mapper2
* <p>
* 人员信息mapper接口
*
* @author 码农猿
* @date 2019-03-25 23:10:08
*/
public interface UserInfo2Mapper {
/**
* 查询所有 人员信息
*
* @return 人员信息 列表
* @author 码农猿
* @date 2019-03-25 23:10:08
*/
List<UserInfo> listAll();
/**
* 根据业务主键id查询
*
* @param userId 业务主键
* @return 人员信息实体
* @author 码农猿
* @date 2019-03-25 23:10:08
*/
UserInfo getByUserId(String userId);
}
DB1-测试Mapper - xml 1
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.mapper.db1.UserInfo1Mapper">
<resultMap id="BaseResultMap" type="com.example.entity.UserInfo">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="user_id" property="userId" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="user_password" property="userPassword" jdbcType="VARCHAR"/>
<result column="real_name" property="realName" jdbcType="VARCHAR"/>
<result column="mobile" property="mobile" jdbcType="VARCHAR"/>
<result column="remark" property="remark" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
<result column="del_flag" property="delFlag" jdbcType="BIT"/>
</resultMap>
<sql id="Base_Column_List">
id,
user_id,
user_name,
user_password,
real_name,
mobile,
remark,
create_time,
update_time,
del_flag
</sql>
<!-- 查询所有记录 -->
<select id="listAll" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM user_info
</select>
<!-- 根据业务主键查询 -->
<select id="getByUserId" resultMap="BaseResultMap"
parameterType="java.lang.String">
SELECT
<include refid="Base_Column_List"/>
FROM user_info
WHERE
user_id = #{userId,jdbcType=VARCHAR}
</select>
</mapper>
DB2-测试Mapper - xml 2
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.mapper.db2.UserInfo2Mapper">
<resultMap id="BaseResultMap" type="com.example.entity.UserInfo">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="user_id" property="userId" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="user_password" property="userPassword" jdbcType="VARCHAR"/>
<result column="real_name" property="realName" jdbcType="VARCHAR"/>
<result column="mobile" property="mobile" jdbcType="VARCHAR"/>
<result column="remark" property="remark" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
<result column="del_flag" property="delFlag" jdbcType="BIT"/>
</resultMap>
<sql id="Base_Column_List">
id,
user_id,
user_name,
user_password,
real_name,
mobile,
remark,
create_time,
update_time,
del_flag
</sql>
<!-- 查询所有记录 -->
<select id="listAll" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM user_info
</select>
<!-- 根据业务主键查询 -->
<select id="getByUserId" resultMap="BaseResultMap"
parameterType="java.lang.String">
SELECT
<include refid="Base_Column_List"/>
FROM user_info
WHERE
user_id = #{userId,jdbcType=VARCHAR}
</select>
</mapper>
Controller测试
package com.example.controller;
import com.example.mapper.db1.UserInfo1Mapper;
import com.example.mapper.db2.UserInfo2Mapper;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 人员信息接口
*
* @author 码农猿
*/
@RestController
@RequestMapping("/user")
public class UserInfoController {
@Resource
private UserInfo1Mapper userInfo1Mapper;
@Resource
private UserInfo2Mapper userInfo2Mapper;
/**
* 获取 db1与 db2的所有人员
* 仅用与 demo项目测试
*
* @author 码农猿
*/
@PostMapping("/list-all")
public Map<String, Object> getAllUser() {
Map<String, Object> result = new HashMap<String, Object>();
//数据库 1 所有人员信息
result.put("DB1-USERS", userInfo1Mapper.listAll());
//数据库 2 所有人员信息
result.put("DB2-USERS", userInfo2Mapper.listAll());
return result;
}
}
测试图示
注:测试查询两个不同数据库的人员信息