Spring Boot + Mybatis 实现动态数据源

动态数据源

在很多具体应用场景的时候,我们需要用到动态数据源的情况,比如多租户的场景,系统登录时需要根据用户信息切换到用户对应的数据库。又比如业务 A 要访问 A 数据库,业务 B 要访问 B 数据库等,都可以使用动态数据源方案进行解决。接下来,我们就来讲解如何实现动态数据源,以及在过程中剖析动态数据源背后的实现原理。

实现案例

本教程案例基于 Spring Boot + Mybatis + MySQL 实现。

数据库设计

首先需要安装好 MySQL 数据库,新建数据库 master,slave,分别创建用户表,用来测试数据源,SQL 脚本如下。

-- ----------------------------------------------------
--  用户
-- ----------------------------------------------------
--  Table structure for `sys_user`
-- ----------------------------------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `name` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) COMMENT '密码',
  `salt` varchar(40) COMMENT '盐',
  `email` varchar(100) COMMENT '邮箱',
  `mobile` varchar(100) COMMENT '手机号',
  `status` tinyint COMMENT '状态  0:禁用   1:正常',
  `dept_id` bigint(20) COMMENT '机构 ID',
  `create_by` varchar(50) COMMENT '创建人',
  `create_time` datetime COMMENT '创建时间',
  `last_update_by` varchar(50) COMMENT '更新人',
  `last_update_time` datetime COMMENT '更新时间',
  `del_flag` tinyint DEFAULT 0 COMMENT '是否删除  -1:已删除  0:正常',
  PRIMARY KEY (`id`),
  UNIQUE INDEX (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户';

新建工程

新建一个 Spring Boot 工程,最终代码结构如下。

 

添加依赖

添加 Spring Boot,Spring Aop,Mybatis,MySQL,Swagger 相关依赖。Swagger 方便用来测试接口。

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>
&lt;groupId&gt;top.ivan.demo&lt;/groupId&gt;
&lt;artifactId&gt;springboot-dynamic-datasource&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;packaging&gt;jar&lt;/packaging&gt;

&lt;name&gt;springboot-dynamic-datasource&lt;/name&gt;
&lt;description&gt;Demo project <span style="color: rgba(0, 0, 255, 1)">for</span> Spring Boot&lt;/description&gt;

&lt;parent&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
    &lt;version&gt;2.0.4.RELEASE&lt;/version&gt;
    &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;

&lt;properties&gt;
    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
    &lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;
    &lt;java.version&gt;1.8&lt;/java.version&gt;
    &lt;mybatis.spring.version&gt;1.3.2&lt;/mybatis.spring.version&gt;
    &lt;swagger.version&gt;2.8.0&lt;/swagger.version&gt;
&lt;/properties&gt;

&lt;dependencies&gt;
       &lt;!-- spring boot --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
        &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;!-- spring aop --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-aop&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;!-- mybatis --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;
        &lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;${mybatis.spring.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;!-- mysql --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;mysql&lt;/groupId&gt;
        &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;!-- swagger --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;io.springfox&lt;/groupId&gt;
        &lt;artifactId&gt;springfox-swagger2&lt;/artifactId&gt;
        &lt;version&gt;${swagger.version}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;io.springfox&lt;/groupId&gt;
        &lt;artifactId&gt;springfox-swagger-ui&lt;/artifactId&gt;
        &lt;version&gt;${swagger.version}&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;

&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;

</project>

配置文件

修改配置文件,添加两个数据源,可以是同一个主机地址的两个数据库 master,slave,也可是两个不同主机的地址,根据实际情况配置。

application.yml

spring:
  datasource:
    master:
      driver-class-name: com.mysql.jdbc.Driver
      type: com.zaxxer.hikari.HikariDataSource
      jdbcUrl: jdbc:mysql://127.0.0.1:3306/master?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
      username: root
      password: 123
    slave:
      driver-class-name: com.mysql.jdbc.Driver
      type: com.zaxxer.hikari.HikariDataSource
      jdbcUrl: jdbc:mysql://127.0.0.1:3306/slave?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
      username: root
      password: 123

启动类

启动类添加 exclude = {DataSourceAutoConfiguration.class}, 以禁用数据源默认自动配置。

数据源默认自动配置会读取 spring.datasource.* 的属性创建数据源,所以要禁用以进行定制。

@ComponentScan(basePackages = "com.louis.springboot") 是扫描范围,都知道不用多说。

DynamicDatasourceApplication.java

package com.louis.springboot.dynamic.datasource;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

/**

  • 启动器

  • @author Louis

  • @date Oct 31, 2018
    */
    @SpringBootApplication(exclude
    = {DataSourceAutoConfiguration.class}) // 禁用数据源自动配置
    @ComponentScan(basePackages = "com.louis.springboot")
    public class DynamicDatasourceApplication {

    public static void main(String[] args) {
    SpringApplication.run(DynamicDatasourceApplication.
    class, args);
    }
    }

数据源配置类

创建一个数据源配置类,主要做以下几件事情:

1. 配置 dao,model,xml mapper 文件的扫描路径。

2. 注入数据源配置属性,创建 master、slave 数据源。

3. 创建一个动态数据源,并装入 master、slave 数据源。

4. 将动态数据源设置到 SQL 会话工厂和事务管理器。

如此,当进行数据库操作时,就会通过我们创建的动态数据源去获取要操作的数据源了。

package com.louis.springboot.dynamic.datasource.config;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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 org.springframework.transaction.PlatformTransactionManager;

import com.louis.springboot.dynamic.datasource.dds.DynamicDataSource;

/**

  • Mybatis 配置

  • @author Louis

  • @date Oct 31, 2018
    */
    @Configuration
    @MapperScan(basePackages
    = {"com.louis.**.dao"}) // 扫描 DAO
    public class MybatisConfig {

    @Bean("master")
    @Primary
    @ConfigurationProperties(prefix
    = "spring.datasource.master")
    public DataSource master() {
    return DataSourceBuilder.create().build();
    }

    @Bean("slave")
    @ConfigurationProperties(prefix
    = "spring.datasource.slave")
    public DataSource slave() {
    return DataSourceBuilder.create().build();
    }

    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource() {
    DynamicDataSource dynamicDataSource
    = new DynamicDataSource();
    Map
    <Object, Object> dataSourceMap = new HashMap<>(2);
    dataSourceMap.put(
    "master", master());
    dataSourceMap.put(
    "slave", slave());
    // 将 master 数据源作为默认指定的数据源
    dynamicDataSource.setDefaultDataSource(master());
    // 将 master 和 slave 数据源作为指定的数据源
    dynamicDataSource.setDataSources(dataSourceMap);
    return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
    SqlSessionFactoryBean sessionFactory
    = new SqlSessionFactoryBean();
    // 配置数据源,此处配置为关键配置,如果没有将 dynamicDataSource 作为数据源则不能实现切换
    sessionFactory.setDataSource(dynamicDataSource());
    sessionFactory.setTypeAliasesPackage(
    "com.louis..model"); // 扫描 Model
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    sessionFactory.setMapperLocations(resolver.getResources(
    "classpath*:
    /sqlmap/*.xml")); // 扫描映射文件
    return sessionFactory;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
    // 配置事务管理, 使用事务时在方法头部添加 @Transactional 注解即可
    return new DataSourceTransactionManager(dynamicDataSource());
    }
    }

动态数据源类

我们上一步把这个动态数据源设置到了 SQL 会话工厂和事务管理器,这样在操作数据库时就会通过动态数据源类来获取要操作的数据源了。

动态数据源类集成了 Spring 提供的 AbstractRoutingDataSource 类,AbstractRoutingDataSource 中获取数据源的方法就是 determineTargetDataSource,而此方法又通过 determineCurrentLookupKey 方法获取查询数据源的 key。

所以如果我们需要动态切换数据源,就可以通过以下两种方式定制:

1. 覆写 determineCurrentLookupKey 方法

通过覆写 determineCurrentLookupKey 方法,从一个自定义的 DynamicDataSourceContextHolder.getDataSourceKey()获取数据源 key 值,这样在我们想动态切换数据源的时候,只要通过  DynamicDataSourceContextHolder.setDataSourceKey(key)  的方式就可以动态改变数据源了。这种方式要求在获取数据源之前,要先初始化各个数据源到 DynamicDataSource 中,我们案例就是采用这种方式实现的,所以在 MybatisConfig 中把 master 和 slave 数据源都事先初始化到 DynamicDataSource 中。

2. 可以通过覆写 determineTargetDataSource,因为数据源就是在这个方法创建并返回的,所以这种方式就比较自由了,支持到任何你希望的地方读取数据源信息,只要最终返回一个 DataSource 的实现类即可。比如你可以到数据库、本地文件、网络接口等方式读取到数据源信息然后返回相应的数据源对象就可以了。

DynamicDataSource.java

package com.louis.springboot.dynamic.datasource.dds;

import java.util.Map;

import javax.sql.DataSource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**

  • 动态数据源实现类

  • @author Louis

  • @date Oct 31, 2018
    */
    public class DynamicDataSource extends AbstractRoutingDataSource {

    /**

    • 如果不希望数据源在启动配置时就加载好,可以定制这个方法,从任何你希望的地方读取并返回数据源
    • 比如从数据库、文件、外部接口等读取数据源信息,并最终返回一个 DataSource 实现类对象即可
      */
      @Override
      protected DataSource determineTargetDataSource() {
      return super.determineTargetDataSource();
      }

    /**

    • 如果希望所有数据源在启动配置时就加载好,这里通过设置数据源 Key 值来切换数据,定制这个方法
      */
      @Override
      protected Object determineCurrentLookupKey() {
      return DynamicDataSourceContextHolder.getDataSourceKey();
      }

    /**

    • 设置默认数据源
    • @param defaultDataSource
      */
      public void setDefaultDataSource(Object defaultDataSource) {
      super.setDefaultTargetDataSource(defaultDataSource);
      }

    /**

    • 设置数据源
    • @param dataSources
      */
      public void setDataSources(Map<Object, Object> dataSources) {
      super.setTargetDataSources(dataSources);
      // 将数据源的 key 放到数据源上下文的 key 集合中,用于切换时判断数据源是否有效
      DynamicDataSourceContextHolder.addDataSourceKeys(dataSources.keySet());
      }
      }

数据源上下文

动态数据源的切换主要是通过调用这个类的方法来完成的。在任何想要进行切换数据源的时候都可以通过调用这个类的方法实现切换。比如系统登录时,根据用户信息调用这个类的数据源切换方法切换到用户对应的数据库。

主要方法介绍:

1. 切换数据源

在任何想要进行切换数据源的时候都可以通过调用这个类的方法实现切换。

    /**
     * 切换数据源
     * @param key
     */
    public static void setDataSourceKey(String key) {contextHolder.set(key);
    }

2. 重置数据源

将数据源重置回默认的数据源。默认数据源通过 DynamicDataSource.setDefaultDataSource(ds) 进行设置。

    /**
     * 重置数据源
     */
    public static void clearDataSourceKey() {contextHolder.remove();
    }

3. 获取当前数据源 key

    /**
     * 获取数据源
     * @return
     */
    public static String getDataSourceKey() {
        return contextHolder.get();}

完整代码如下

DynamicDataSourceContextHolder.java

package com.louis.springboot.dynamic.datasource.dds;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**

  • 动态数据源上下文

  • @author Louis

  • @date Oct 31, 2018
    */
    public class DynamicDataSourceContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>() {
    /**
    * 将 master 数据源的 key 作为默认数据源的 key
    */
    @Override
    protected String initialValue() {
    return "master";
    }
    };

    /**

    • 数据源的 key 集合,用于切换时判断数据源是否存在
      */
      public static List<Object> dataSourceKeys = new ArrayList<>();

    /**

    • 切换数据源
    • @param key
      */
      public static void setDataSourceKey(String key) {
      contextHolder.set(key);
      }

    /**

    • 获取数据源
    • @return
      */
      public static String getDataSourceKey() {
      return contextHolder.get();
      }

    /**

    • 重置数据源
      */
      public static void clearDataSourceKey() {
      contextHolder.remove();
      }

    /**

    • 判断是否包含数据源
    • @param key 数据源 key
    • @return
      */
      public static boolean containDataSourceKey(String key) {
      return dataSourceKeys.contains(key);
      }

    /**

    • 添加数据源 keys
    • @param keys
    • @return
      */
      public static boolean addDataSourceKeys(Collection<? extends Object> keys) {
      return dataSourceKeys.addAll(keys);
      }
      }

注解式数据源

到这里,在任何想要动态切换数据源的时候,只要调用  DynamicDataSourceContextHolder.setDataSourceKey(key)  就可以完成了。

接下来我们实现通过注解的方式来进行数据源的切换,原理就是添加注解(如 @DataSource(value="master")),然后实现注解切面进行数据源切换。

创建一个动态数据源注解,拥有一个 value 值,用于标识要切换的数据源的 key。

DataSource.java

package com.louis.springboot.dynamic.datasource.dds;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**

  • 动态数据源注解

  • @author Louis

  • @date Oct 31, 2018
    */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface DataSource {

    /**

    • 数据源 key 值
    • @return
      */
      String value();

}

创建一个 AOP 切面,拦截带 @DataSource 注解的方法,在方法执行前切换至目标数据源,执行完成后恢复到默认数据源。

DynamicDataSourceAspect.java

package com.louis.springboot.dynamic.datasource.dds;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**

  • 动态数据源切换处理器

  • @author Louis

  • @date Oct 31, 2018
    */
    @Aspect
    @Order(
    -1) // 该切面应当先于 @Transactional 执行
    @Component
    public class DynamicDataSourceAspect {

    /**

    • 切换数据源
    • @param point
    • @param dataSource
      */
      @Before(
      "@annotation(dataSource))")
      public void switchDataSource(JoinPoint point, DataSource dataSource) {
      if (!DynamicDataSourceContextHolder.containDataSourceKey(dataSource.value())) {
      System.out.println(
      "DataSource [{}] doesn't exist, use default DataSource [{}] " + dataSource.value());
      }
      else {
      // 切换数据源
      DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
      System.out.println(
      "Switch DataSource to [" + DynamicDataSourceContextHolder.getDataSourceKey()
      + "] in Method [" + point.getSignature() + "]");
      }
      }

    /**

    • 重置数据源
    • @param point
    • @param dataSource
      */
      @After(
      "@annotation(dataSource))")
      public void restoreDataSource(JoinPoint point, DataSource dataSource) {
      // 将数据源置为默认数据源
      DynamicDataSourceContextHolder.clearDataSourceKey();
      System.out.println(
      "Restore DataSource to [" + DynamicDataSourceContextHolder.getDataSourceKey()
      + "] in Method [" + point.getSignature() + "]");
      }
      }

到这里,动态数据源相关的处理代码就完成了。

编写用户业务代码

接下来编写用户查询业务代码,用来进行测试,只需添加一个查询接口即可。

编写一个控制器,包含两个查询方法,分别注解 master 和 slave 数据源。

SysUserController.java

package com.louis.springboot.dynamic.datasource.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.louis.springboot.dynamic.datasource.dds.DataSource;
import com.louis.springboot.dynamic.datasource.service.SysUserService;

/**

  • 用户控制器

  • @author Louis

  • @date Oct 31, 2018
    */
    @RestController
    @RequestMapping(
    "user")
    public class SysUserController {

    @Autowired
    private SysUserService sysUserService;

    @DataSource(value="master")
    @PostMapping(value
    ="/findAll")
    public Object findAll() {
    return sysUserService.findAll();
    }

    @DataSource(value="slave")
    @PostMapping(value
    ="/findAll2")
    public Object findAll2() {
    return sysUserService.findAll();
    }

}

 

下面是正常的业务代码,没有什么好说明的,直接贴代码了。

SysUser.java

public class SysUser {
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Long id;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String name;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String password;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String salt;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String email;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String mobile;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Byte status;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Long deptId;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String deptName;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Byte delFlag;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String createBy;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date createTime;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String lastUpdateBy;

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date lastUpdateTime;<br><br>  ...setter and getter

}

 

SysUserMapper.java

package com.louis.springboot.dynamic.datasource.dao;

import java.util.List;

import com.louis.springboot.dynamic.datasource.model.SysUser;

public interface SysUserMapper {
int deleteByPrimaryKey(Long id);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> insert(SysUser record);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> insertSelective(SysUser record);

SysUser selectByPrimaryKey(Long id);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> updateByPrimaryKeySelective(SysUser record);

</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> updateByPrimaryKey(SysUser record);

List</span>&lt;SysUser&gt;<span style="color: rgba(0, 0, 0, 1)"> findAll();

}

 

SysUserMapper.xml

<?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.louis.springboot.dynamic.datasource.dao.SysUserMapper">
  <resultMap id="BaseResultMap" type="com.louis.springboot.dynamic.datasource.model.SysUser">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="password" jdbcType="VARCHAR" property="password" />
    <result column="salt" jdbcType="VARCHAR" property="salt" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="mobile" jdbcType="VARCHAR" property="mobile" />
    <result column="status" jdbcType="TINYINT" property="status" />
    <result column="dept_id" jdbcType="BIGINT" property="deptId" />
    <result column="create_by" jdbcType="BIGINT" property="createBy" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="last_update_by" jdbcType="BIGINT" property="lastUpdateBy" />
    <result column="last_update_time" jdbcType="TIMESTAMP" property="lastUpdateTime" />
    <result column="del_flag" jdbcType="TINYINT" property="delFlag" />
  </resultMap>
  <sql id="Base_Column_List">
    id, name, password, salt, email, mobile, status, dept_id, create_by, create_time, 
    last_update_by, last_update_time, del_flag
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from sys_user
    where id = #{id,jdbcType=BIGINT}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from sys_user
    where id = #{id,jdbcType=BIGINT}
  </delete>
  <insert id="insert" parameterType="com.louis.springboot.dynamic.datasource.model.SysUser">
    insert into sys_user (id, name, password, 
      salt, email, mobile, 
      status, dept_id, create_by, 
      create_time, last_update_by, last_update_time, 
      del_flag)
    values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, 
      #{salt,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{mobile,jdbcType=VARCHAR}, 
      #{status,jdbcType=TINYINT}, #{deptId,jdbcType=BIGINT}, #{createBy,jdbcType=BIGINT}, 
      #{createTime,jdbcType=TIMESTAMP}, #{lastUpdateBy,jdbcType=BIGINT}, #{lastUpdateTime,jdbcType=TIMESTAMP}, 
      #{delFlag,jdbcType=TINYINT})
  </insert>
  <insert id="insertSelective" parameterType="com.louis.springboot.dynamic.datasource.model.SysUser">
    insert into sys_user
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="password != null">
        password,
      </if>
      <if test="salt != null">
        salt,
      </if>
      <if test="email != null">
        email,
      </if>
      <if test="mobile != null">
        mobile,
      </if>
      <if test="status != null">
        status,
      </if>
      <if test="deptId != null">
        dept_id,
      </if>
      <if test="createBy != null">
        create_by,
      </if>
      <if test="createTime != null">
        create_time,
      </if>
      <if test="lastUpdateBy != null">
        last_update_by,
      </if>
      <if test="lastUpdateTime != null">
        last_update_time,
      </if>
      <if test="delFlag != null">
        del_flag,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=BIGINT},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        #{password,jdbcType=VARCHAR},
      </if>
      <if test="salt != null">
        #{salt,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        #{email,jdbcType=VARCHAR},
      </if>
      <if test="mobile != null">
        #{mobile,jdbcType=VARCHAR},
      </if>
      <if test="status != null">
        #{status,jdbcType=TINYINT},
      </if>
      <if test="deptId != null">
        #{deptId,jdbcType=BIGINT},
      </if>
      <if test="createBy != null">
        #{createBy,jdbcType=BIGINT},
      </if>
      <if test="createTime != null">
        #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="lastUpdateBy != null">
        #{lastUpdateBy,jdbcType=BIGINT},
      </if>
      <if test="lastUpdateTime != null">
        #{lastUpdateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="delFlag != null">
        #{delFlag,jdbcType=TINYINT},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.louis.springboot.dynamic.datasource.model.SysUser">
    update sys_user
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        password = #{password,jdbcType=VARCHAR},
      </if>
      <if test="salt != null">
        salt = #{salt,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="mobile != null">
        mobile = #{mobile,jdbcType=VARCHAR},
      </if>
      <if test="status != null">
        status = #{status,jdbcType=TINYINT},
      </if>
      <if test="deptId != null">
        dept_id = #{deptId,jdbcType=BIGINT},
      </if>
      <if test="createBy != null">
        create_by = #{createBy,jdbcType=BIGINT},
      </if>
      <if test="createTime != null">
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="lastUpdateBy != null">
        last_update_by = #{lastUpdateBy,jdbcType=BIGINT},
      </if>
      <if test="lastUpdateTime != null">
        last_update_time = #{lastUpdateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="delFlag != null">
        del_flag = #{delFlag,jdbcType=TINYINT},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.louis.springboot.dynamic.datasource.model.SysUser">
    update sys_user
    set name = #{name,jdbcType=VARCHAR},
      password = #{password,jdbcType=VARCHAR},
      salt = #{salt,jdbcType=VARCHAR},
      email = #{email,jdbcType=VARCHAR},
      mobile = #{mobile,jdbcType=VARCHAR},
      status = #{status,jdbcType=TINYINT},
      dept_id = #{deptId,jdbcType=BIGINT},
      create_by = #{createBy,jdbcType=BIGINT},
      create_time = #{createTime,jdbcType=TIMESTAMP},
      last_update_by = #{lastUpdateBy,jdbcType=BIGINT},
      last_update_time = #{lastUpdateTime,jdbcType=TIMESTAMP},
      del_flag = #{delFlag,jdbcType=TINYINT}
    where id = #{id,jdbcType=BIGINT}
  </update>
  <select id="findAll" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from sys_user
  </select>
</mapper>

 

SysUserService.java

package com.louis.springboot.dynamic.datasource.service;

import java.util.List;

import com.louis.springboot.dynamic.datasource.model.SysUser;

/**

  • 用户管理

  • @author Louis

  • @date Oct 31, 2018
    */
    public interface SysUserService {

    /**

    • 查找全部用户信息
    • @return
      */
      List
      <SysUser> findAll();
      }

 

SysUserServiceImpl.java

package com.louis.springboot.dynamic.datasource.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.louis.springboot.dynamic.datasource.dao.SysUserMapper;
import com.louis.springboot.dynamic.datasource.model.SysUser;
import com.louis.springboot.dynamic.datasource.service.SysUserService;

@Service
public class SysUserServiceImpl implements SysUserService {

@Autowired
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> SysUserMapper sysUserMapper;

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 查找全部用户信息
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
 <span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;SysUser&gt;<span style="color: rgba(0, 0, 0, 1)"> findAll() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sysUserMapper.findAll();
}

}

 

测试效果

启动系统,访问 http://localhost:8080/swagger-ui.html,分别测试两个接口,成功返回数据。

user/findAll (master 数据源)

 

user/findAll2 (slave 数据源)

 

 

源码下载

码云:https://gitee.com/liuge1988/spring-boot-demo.git


作者:朝雨忆轻尘
出处:https://www.cnblogs.com/xifengxiaoma/ 
版权所有,欢迎转载,转载请注明原文作者及出处。