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