SpringBoot+mybatis整合多个数据源附源码

核心技术点介绍

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;
    }
}

测试图示
注:测试查询两个不同数据库的人员信息
在这里插入图片描述

源码地址
https://github.com/mengq0815/spring-boot-example
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38011415/article/details/88832364