springboot实现读取多数据源datasource的动态切换

Posted 健康平安的活着

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot实现读取多数据源datasource的动态切换相关的知识,希望对你有一定的参考价值。

一 配置操作

1.1 工程结构

1.2  pom文件

<?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>
  <!-- 引入springboot 的父类-->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.guolu.data.sync</groupId>
  <artifactId>dky-guolu-data-sync</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>dky-guolu-data-sync</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- springBoot的启动器 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.0.1.RELEASE</version>
    </dependency>
    <!-- web启动器 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
      <version>2.0.1.RELEASE</version>
    </dependency>
    <!-- Mybatis启动器 -->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.9</version>
    </dependency>
    <!-- mysql数据库驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.3</version>
    </dependency>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>20.0</version>
    </dependency>
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.4</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

  <build>

  </build>
</project>

1.3 resources配置文件

server:
  port: 9090
spring:
  datasource:
    druid:
      guoluoMain:  #数据源1
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=UTF-8&useSSL=false
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource
        initialSize: 5
        maxActive: 50
        minIdle: 5
        maxWait: 10000
        timeBetweenEvictionRunsMillis: 600000
        minEvictableIdleTimeMillis: 1800000
        removeAbandonedTimeout: 180
        validationQuery: SELECT 1
        removeAbandoned: true
        testWhileIdle: true
        testOnBorrow: true
        testOnReturn: false
      guoluoBack:  #数据源2
          driverClassName: com.mysql.jdbc.Driver
          url: jdbc:mysql://localhost:3306/security_db?useUnicode=true&characterEncoding=UTF-8&useSSL=false
          username: root
          password: root
          type: com.alibaba.druid.pool.DruidDataSource
          initialSize: 5
          maxActive: 50
          minIdle: 5
          maxWait: 10000
          timeBetweenEvictionRunsMillis: 600000
          minEvictableIdleTimeMillis: 1800000
          removeAbandonedTimeout: 180
          validationQuery: SELECT 1
          removeAbandoned: true
          testWhileIdle: true
          testOnBorrow: true
          testOnReturn: false
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.guolu.data.sync.model
  configuration:
    #增加打印sql语句,一般用于本地开发测试
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#分页插件
  pagehelper:
    helper-dialect: mysql
    params: count=countSql
    reasonable: true    #开启优化,如果开启优化,在分页页码结果没有数据的时候,会显示有数据的页码数据
    support-methods-arguments: true #是否支持接口参数来传递分页参数,默认false

1.4 读取数据源的配置文件

1.DataSourceChangeHelper

package com.guolu.data.sync.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Li GQ 2018/11/2
 */
public class DataSourceChangeHelper {
    private static Logger logger = LoggerFactory.getLogger(DataSourceChangeHelper.class);

    public static void doChange(String sourceType, IDataSourceChangeCallbackWithoutResult action) {
        try {
            DynamicDataSource.setDataSource(sourceType);
            action.actionWithoutResult();
        } catch (Exception e) {
            logger.error("", e);
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }

    public static <T> T doChangeWithResult(String sourceType, IDataSourceChangeCallback action) {
        Object result = null;
        try {
            DynamicDataSource.setDataSource(sourceType);
            result = action.actionWithResult();
        } catch (Exception e) {
            logger.error("", e);
        } finally {
            DynamicDataSource.clearDataSource();
        }
        return result == null ? null : (T) result;
    }
}

 2.DataSourceNames

package com.guolu.data.sync.config;

/**
 * 多数据源 key
 */
public interface DataSourceNames {
    String guoluMain ="guoluMain";
    String guoluBack ="guoluBack";

}

3.DynamicDataSource

package com.guolu.data.sync.config;

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

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(new HashMap<Object,Object>(targetDataSources));
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }

}

4.DynamicDataSourceConfig

package com.guolu.data.sync.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
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 javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置多数据源
 */
@Configuration
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid.guoluomain")  //spring.datasource.druid.guoluoMain
    public DataSource guoLuMainDataSource(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties("spring.datasource.druid.guoluoback")
    public DataSource guoLuBackDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource guoLuMainDataSource,DataSource guoLuBackDataSource) {
        Map<String, DataSource> targetDataSources = new HashMap<>();
        targetDataSources.put("guoluMain", guoLuMainDataSource);
        targetDataSources.put("guoluBack", guoLuBackDataSource);
        return new DynamicDataSource(guoLuMainDataSource, targetDataSources);
    }
}

5.IDataSourceChangeCallback

package com.guolu.data.sync.config;

/**
 * @author Li GQ 2018/11/2
 */
@FunctionalInterface
public interface IDataSourceChangeCallback<T> {

    T actionWithResult();
}

6.IDataSourceChangeCallbackWithoutResult

package com.guolu.data.sync.config;

/**
 * @author Li GQ 2018/11/2
 */
@FunctionalInterface
public interface IDataSourceChangeCallbackWithoutResult {

    void actionWithoutResult();
}

1.5 controller

1.roleController

package com.guolu.data.sync.controller;

import com.github.pagehelper.PageHelper;
import com.guolu.data.sync.model.Role;
import com.guolu.data.sync.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @ClassName: RoleController
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2021/09/07 00:10:46 
 * @Version: V1.0
 **/
@Controller
@RequestMapping("/roles")
public class RoleController {
    @Autowired
    private RoleService roleService;
    @GetMapping("/getAllRole")
    @ResponseBody
    public Object getAllPerson(Model model, @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum){
        PageHelper.startPage(pageNum,5);
        List<Role> list = this.roleService.findRoleAll();
        return list;
    }
}

2. userController

package com.guolu.data.sync.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.guolu.data.sync.model.Users;
import com.guolu.data.sync.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * @ClassName: UserController
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2020/07/29 15:45:36
 * @Version: V1.0
 **/
@Controller
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService usersService;
    @GetMapping("/getAllPerson")
    public String getAllPerson(Model model,@RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum){
        PageHelper.startPage(pageNum,5);
        List<Users> list = this.usersService.findUserAll();
        PageInfo<Users> pageInfo = new PageInfo<Users>(list);
        model.addAttribute("pageInfo",pageInfo);
        //model.addAttribute("list", list);
        return "user_list";
    }

    /**
     * 页面跳转
     */
    @RequestMapping("/{page}")
    public String showPage(@PathVariable String page){
        System.out.println("进来了!!!"+page);
        return page;
    }

    /**
     * 查询全部用户
     */
    @RequestMapping("/findUserAll")
    public String findUserAll(Model model){
        List<Users> list = this.usersService.findUserAll();
        model.addAttribute("list", list);
        return "showUsers";
    }





}

1.6 service

1.userService

package com.guolu.data.sync.service;

import com.guolu.data.sync.model.Users;

import java.util.List;

public interface UserService {
    List<Users> findUserAll();
}

2.roleService

package com.guolu.data.sync.service;

import com.guolu.data.sync.model.Role;

import java.util.List;

public interface RoleService  {
    List<Role> findRoleAll();
}

3.实现类

package com.guolu.data.sync.service.impl;

import com.guolu.data.sync.config.DataSourceChangeHelper;
import com.guolu.data.sync.config.DataSourceNames;
import com.guolu.data.sync.dao.RoleMapper;
import com.guolu.data.sync.model.Role;
import com.guolu.data.sync.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @ClassName: RoleServiceImpl
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2021/09/07 00:13:27 
 * @Version: V1.0
 **/
@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Override
    public List<Role> findRoleAll() {
        List<Role> list= DataSourceChangeHelper.doChangeWithResult(DataSourceNames.guoluBack,
                ()->roleMapper.selectUsersAll());//读从库
        return list;
    }
}

package com.guolu.data.sync.service.impl;

import com.guolu.data.sync.config.DataSourceChangeHelper;
import com.guolu.data.sync.config.DataSourceNames;
import com.guolu.data.sync.dao.UsersMapper;
import com.guolu.data.sync.model.Users;
import com.guolu.data.sync.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @ClassName: UserServiceImpl
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2020/07/29 17:16:59
 * @Version: V1.0
 **/
@Service
@Transactional
public class UserServiceImpl  implements UserService {
    @Autowired
    private UsersMapper usersMapper;
    @Override
    public List<Users> findUserAll() {
        List<Users> list= DataSourceChangeHelper.doChangeWithResult(DataSourceNames.guoluMain,
                ()->usersMapper.selectUsersAll());//读从库
        return list;
    }

}

1.7 dao

1.roleMapper

package com.guolu.data.sync.dao;

import com.guolu.data.sync.model.Role;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface RoleMapper {
    List<Role> selectUsersAll();
}

2.userMapper

package com.guolu.data.sync.dao;


import com.guolu.data.sync.model.Users;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UsersMapper {

	List<Users> selectUsersAll();

}

1.8 resouces/mapper

1.userMapper

<?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.guolu.data.sync.dao.RoleMapper" >

 <!-- 查询用户信息 -->
    <select id="selectUsersAll" resultType="com.guolu.data.sync.model.Role">
		select id,role_name as roleName from t_role
	</select>

</mapper>

2.roleMapper

<?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.guolu.data.sync.dao.UsersMapper" >
<!-- 添加信息 -->
  <insert id="insertUser" parameterType="com.guolu.data.sync.model.Users">
     insert into tb_users(name,age) values(#{name,jdbcType=VARCHAR},#{age,jdbcType=BIGINT})
</insert>
 <!-- 查询用户信息 -->
    <select id="selectUsersAll" resultType="com.guolu.data.sync.model.Users">
		select id,name,age from tb_users
	</select>
    <!--通过id查询信息 -->
    <select id="selectUsersById" resultType="com.guolu.data.sync.model.Users">
		select id,name,age from tb_users where id = #{value}
	</select>
    <!-- 通过id修改 -->
    <update id="updateUser" parameterType="com.guolu.data.sync.model.Users">
		update tb_users set name=#{name} ,age=#{age} where id=#{id}
	</update>
	<!-- 通过id修改,判断空处理 -->
	<update id="updateUserIfNotNull" parameterType="com.guolu.data.sync.model.Users">
		update tb_users
		<set>
		<if test="name!=null">
			name=#{name},
		</if>
		<if test="age!=null">
			age=#{age},
		</if>
		</set>
		where id=#{id}
	</update>
    <!-- 删除数据 -->
    <delete id="deleteUserById">
		delete from tb_users where id = #{value}
	</delete>
</mapper>

1.9  前端页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>展示用户数据</title>
</head>
<body>
	<table border="1" style="width:300px;">
		<tr>
			<th>用户ID</th>
			<th>用户姓名</th>
			<th>用户年龄</th>
		</tr>
		<tr th:each="user : ${list}">
			<td th:text="${user.id}"></td>
			<td th:text="${user.name}"></td>
			<td th:text="${user.age}"></td>
		</tr>
	</table>
</body>
</html>

1.10 启动类

package com.guolu.data.sync;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

/**
 * Hello world!
 *
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("com.guolu.data.sync.dao") //@MapperScan 用户扫描MyBatis的Mapper
public class App 
{
    public static void main( String[] args )
    {

        SpringApplication.run(App.class, args);
        System.out.println("=============springboot 分页启动完成=======!!!");
    }
}

1.11 测试类

1.访问主库

2.访问从库:

以上是关于springboot实现读取多数据源datasource的动态切换的主要内容,如果未能解决你的问题,请参考以下文章

springboot(mybatis)多数据源:mysql+mysql

springboot(mybatis)多数据源:mysql+mysql

springboot(mybatis)多数据源:mysql+mysql

springboot(mybatis)多数据源:mysql+mysql

springboot实现读取多数据源datasource的动态切换

springboot 多数据源 怎么读取url