• 自定义动态数据源


    准备

    • mysql
    • spring boot
    • 配置依赖

    在这里插入图片描述

    • 配置文件
    # 数据源配置
    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        ds:
          # 主库数据源
          master:
            url: jdbc:mysql://192.168.10.10:3306/test08?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
            username: root
            password: root
          # 从库数据源
          slave:
            # 从数据源开关/默认关闭
            url: jdbc:mysql://192.168.10.10:3306/test09?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
            username: root
            password: root
          # 初始连接数
        initialSize: 5
        # 最小连接池数量
        minIdle: 10
        # 最大连接池数量
        maxActive: 20
        # 配置获取连接等待超时的时间
        maxWait: 60000
        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        timeBetweenEvictionRunsMillis: 60000
        # 配置一个连接在池中最小生存的时间,单位是毫秒
        minEvictableIdleTimeMillis: 300000
        # 配置一个连接在池中最大生存的时间,单位是毫秒
        maxEvictableIdleTimeMillis: 900000
        # 配置检测连接是否有效
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        webStatFilter:
          enabled: true
        statViewServlet:
          enabled: true
          # 设置白名单,不填则允许所有访问
          allow:
          url-pattern: /druid/*
          # 控制台管理用户名和密码
          login-username: tienchin
          login-password: 123456
        filter:
          stat:
            enabled: true
            # 慢SQL记录
            log-slow-sql: true
            slow-sql-millis: 1000
            merge-sql: true
          wall:
            config:
              multi-statement-allow: true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    在这里插入图片描述

    业务流程分析

    1. 自定义一个注解 @DataSource,将来可能加在 service 方法或者是该类上,表示方法或者类上的所有方法都是用某一个数据源。

    2. 对于第一步,如果某个方法上面有 @DataSource 注解,那么就将该方法需要使用的数据源名称存入到 ThreadLocal 当中。

    3. 自定义切面,在切面中去解析 @DataSource 注解,当一个方法或者类上面有 @DataSource 注解的时候,将 @DataSource 注解所标记的数据源存入 ThreadLocal 中。

    4. 最后,当 Mapper 执行的时候,需要 DataSource,他会自动去 AbstractRoutingDataSource 类中去查找需要的数据源,我们只需要在 AbstractRoutingDataSource 中返回 ThreadLocal 中的值即可。


    代码实现

     

    定义注解:@DataSource

    
    package org.javaboy.dd;
    
    import org.javaboy.dd.dataSource.DataSourceType;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-14 21:14
     *  这个注解,将来可也加载到某一个 service 类或者方法上,通过 value 属性来指定类或者方法应该使用那个数据源
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD,ElementType.TYPE})
    public @interface DataSource {
    
        /**
         *  如果一个方法上,加了 @DataSource 注解,但是没有指定数据源的名称,那么默认就是用 master 数据源
         * @return
         */
        String value() default DataSourceType.DEFAULT_DS_NAME;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

     

    定义一个 contextHolder 来存储当前线程使用的数据源:

    package org.javaboy.dd.dataSource;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-14 21:20
     *
     * 这个类用来存储当前线程所使用的的数据源名称
     */
    public class DynamicDataSourceContextHolder {
    
        private static ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal();
    
        public static void setDataSourceType(String dsType){
            CONTEXT_HOLDER.set(dsType);
        }
    
        public static String getDataSourceType(){
          return   CONTEXT_HOLDER.get();
        }
    
        /**
         *  清除
         */
        public static void clearDataSourceType(){
            CONTEXT_HOLDER.remove();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    定义一个切面,动态的读取业务层注解中的值:

    package org.javaboy.dd.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.javaboy.dd.DataSource;
    import org.javaboy.dd.dataSource.DynamicDataSourceContextHolder;
    import org.springframework.core.annotation.AnnotationUtils;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import org.springframework.util.ObjectUtils;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-14 21:26
     */
    @Component
    @Aspect
    @Order(11)
    public class DataSourceAspect {
    
        /**
         * @annotation(org.javaboy.dd.DatadSource) 表示方法上有 datasource 将方法拦截下来
         * @within(org.javaboy.dd.DatadSource) 表示类上有 datasource 将类中方法拦截下来
         */
        @Pointcut("@annotation(org.javaboy.dd.DataSource) || @within(org.javaboy.dd.DataSource)")
        public void pc(){
    
        }
    
        @Around("pc()")
        public Object around(ProceedingJoinPoint point){
            DataSource dataSource = getDatadSource(point);
            if (dataSource !=null){
                // 获取直接中数据源的名称
                String value = dataSource.value();
                DynamicDataSourceContextHolder.setDataSourceType(value);
            }
    
            try {
                return point.proceed();
            }catch (Throwable e){
                e.printStackTrace();
            }finally {
                DynamicDataSourceContextHolder.clearDataSourceType();
            }
    
            return null;
        }
    
    
        private DataSource getDatadSource(ProceedingJoinPoint point) {
            // 获取方法上的有效注解
            MethodSignature signature = (MethodSignature) point.getSignature();
            // 查找方法上的注解
            DataSource annotation = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
            // 如果不为空,则方法上有该注解
            if (!ObjectUtils.isEmpty(annotation)) {
                return annotation;
            }
            return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    读取配置文件的数据源的值:

    package org.javaboy.dd.dataSource;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    import javax.sql.DataSource;
    import java.util.Map;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 19:07
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    public class DruidProperties {
    
        private String type;
    
        private String driverClassName;
    
        private Map<String, Map<String, String>> ds;
    
        private Integer initialSize;
    
        private Integer minIdle;
    
        private Integer maxActive;
    
        private Integer maxWait;
    
        /**
         * 一会在外部构造好一个 dataSource 对象,但是对象只包含三个核心属性,url,username,password
         * 在这个方法中,给这个对象设置公共的属性
         *
         * @param dataSource
         * @return
         */
        public DataSource dataSource(DruidDataSource dataSource) {
            dataSource.setInitialSize(initialSize);
            dataSource.setMinIdle(minIdle);
            dataSource.setMaxActive(maxActive);
            dataSource.setMaxWait(maxWait);
            return dataSource;
        }
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public String getDriverClassName() {
            return driverClassName;
        }
    
        public void setDriverClassName(String driverClassName) {
            this.driverClassName = driverClassName;
        }
    
        public Map<String, Map<String, String>> getDs() {
            return ds;
        }
    
        public void setDs(Map<String, Map<String, String>> ds) {
            this.ds = ds;
        }
    
        public Integer getInitialSize() {
            return initialSize;
        }
    
        public void setInitialSize(Integer initialSize) {
            this.initialSize = initialSize;
        }
    
        public Integer getMaxActive() {
            return maxActive;
        }
    
        public void setMaxActive(Integer maxActive) {
            this.maxActive = maxActive;
        }
    
        public Integer getMinIdle() {
            return minIdle;
        }
    
        public void setMinIdle(Integer minIdle) {
            this.minIdle = minIdle;
        }
    
        public Integer getMaxWait() {
            return maxWait;
        }
    
        public void setMaxWait(Integer maxWait) {
            this.maxWait = maxWait;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    加载数据源的配置:

    package org.javaboy.dd.dataSource;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 19:20
     *  加载数据源的配置
     */
    @Component
    @EnableConfigurationProperties(DruidProperties.class)
    public class LoadDataSource {
    
        @Autowired
        private DruidProperties druidProperties;
    
        /**
        * 将数据源数据存入 map 集合中
        */
        public Map<String, DataSource> loadAllDataSource() {
            HashMap<String, DataSource> map = new HashMap<>();
            Map<String, Map<String, String>> ds = druidProperties.getDs();
            Set<String> keySet = ds.keySet();
            try {
                for (String key : keySet) {
                    map.put(key, druidProperties.dataSource((DruidDataSource) DruidDataSourceFactory.createDataSource(ds.get(key))));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return map;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    继承 AbstractRoutingDataSource 抽象类,重写方法:

    package org.javaboy.dd.dataSource;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    import org.springframework.stereotype.Component;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 19:29
     */
    @Component
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        /**
         *  拿到数据源之后,我们要告诉该类去找 LoadDataSource 中的 loadAllDataSource() 方法,查找信息
         */
        public DynamicDataSource(LoadDataSource loadDataSource) {
            // 1. 设置所有的数据源
            Map<String, DataSource> allDs = loadDataSource.loadAllDataSource();
            super.setTargetDataSources(new HashMap<>(allDs));
            // 2,设置默认的数据源
            // 将来,并不是所有的方法上都有 @dataSource 的注解,对于那些没有 @DataSource 注解的方法,该使用那个数据源
            super.setDefaultTargetDataSource(allDs.get(DataSourceType.DEFAULT_DS_NAME));
            // 3. 调用父类中的方法
            super.afterPropertiesSet();
        }
    
        /**
         * 这个方法用来返回数据源名称,当系统需要获取数据源的时候,会自动调用该方法获取数据源的名称
         * @return
         */
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDataSourceType();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    定义一个常量类:

    package org.javaboy.dd.dataSource;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 19:40
     */
    public interface DataSourceType {
    
        /**
         *  默认的数据源
         */
        String DEFAULT_DS_NAME = "master";
    
        /**
         *  session key
         */
        String DS_SESSION_KEY = "ds_session_key";
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    创建数据库,model mapper service controller

    /*
     Navicat Premium Data Transfer
    
     Source Server         : TienChin
     Source Server Type    : MariaDB
     Source Server Version : 100311
     Source Host           : 192.168.10.10:3306
     Source Schema         : test08
    
     Target Server Type    : MariaDB
     Target Server Version : 100311
     File Encoding         : 65001
    
     Date: 16/08/2022 20:19:17
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` int(32) DEFAULT NULL,
      `name` varchar(64) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
      `age` int(10) DEFAULT NULL
    ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES (1, 'zhangsan', 18);
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    --------------------------------
    
    /*
     Navicat Premium Data Transfer
    
     Source Server         : TienChin
     Source Server Type    : MariaDB
     Source Server Version : 100311
     Source Host           : 192.168.10.10:3306
     Source Schema         : test09
    
     Target Server Type    : MariaDB
     Target Server Version : 100311
     File Encoding         : 65001
    
     Date: 16/08/2022 20:20:30
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` int(32) DEFAULT NULL,
      `name` varchar(64) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
      `age` int(10) DEFAULT NULL
    ) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES (2, 'lisi', 99);
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    package org.javaboy.dd.model;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 19:56
     */
    
    public class User {
    
        private Integer  id;
    
        private String name;
    
        private Integer age;
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    package org.javaboy.dd.mapper;
    
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    import org.javaboy.dd.model.User;
    
    import java.util.List;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 19:59
     */
    @Mapper
    public interface UserMapper {
    
        @Select("select * from user")
        List<User> getAllUsers();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    package org.javaboy.dd.service;
    
    import org.javaboy.dd.DataSource;
    import org.javaboy.dd.mapper.UserMapper;
    import org.javaboy.dd.model.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 20:01
     */
    @Service
    @DataSource()
    public class UserService {
    
        @Autowired
        private UserMapper userMapper;
    
        public List<User> getAllUser(){
            return userMapper.getAllUsers();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    package org.javaboy.dd.controller;
    
    import org.javaboy.dd.model.User;
    import org.javaboy.dd.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-15 20:03
     */
    @RestController
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @GetMapping("hello")
        public List<User> hello(){
            return userService.getAllUser();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    网页上切换数据源


    定义接口,传入参数,切换数据源:

    package org.javaboy.dd.controller;
    
    import org.javaboy.dd.dataSource.DataSourceType;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpSession;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-16 19:05
     */
    @RestController
    public class DataSourceController {
    
        private static  final Logger logger = LoggerFactory.getLogger(DataSourceController.class);
    
        /**
         * 修改数据源的接口
         * 数据源的修改就存储到 httpSession 中去, 跟当前回话绑定
         * @param dsType
         */
        @PostMapping("/dsType")
        public void setDsType(String dsType, HttpSession session) {
            session.setAttribute(DataSourceType.DS_SESSION_KEY,dsType);
            logger.info("数据源切换为:{}",dsType);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    定义全局切面,切换数据源:

    package org.javaboy.dd.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.javaboy.dd.dataSource.DataSourceType;
    import org.javaboy.dd.dataSource.DynamicDataSourceContextHolder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpSession;
    
    /**
     * @author: yueLQ
     * @date: 2022-08-16 19:13
     * 

    * 该切面去管理,我们传入的数据源,接收到数据源之后,全局所有的 service 方法,使用该数据源 *

    * 当我们配置了全局的数据源切换和注解的数据源 @DataSource() 切换时 * 有 @DataSource 注解,则使用注解,没有注解的使用全局数据源,使用 @Order() 注解 * 业务上优先级高,代码上的优先级要低,让带有 @dataSource() 的注解后执行 */ @Component @Aspect @Order(10) public class GloalDataSourceAspect { @Autowired private HttpSession httpSession; /** * 所有的 service 方法都切入 */ @Pointcut("execution(* org.javaboy.dd.service.*.*(..))") public void pc() { } /** * 环绕通知 * * @param point */ @Around("pc()") public Object aroud(ProceedingJoinPoint point) { // 从 session 中,把我们的数据源的名称读出来。出入到 contextHolder 中去 DynamicDataSourceContextHolder.setDataSourceType((String) httpSession.getAttribute(DataSourceType.DS_SESSION_KEY)); try { return point.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } finally { // 清空 DynamicDataSourceContextHolder.clearDataSourceType(); } return null; } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    定义前台页面,引入 jquery

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <script src="jquery-3.4.1.js">script>
    head>
    <body>
    <div>
        请选择数据源:
        <select name="" id="" onchange="dsChange(this.options[this.options.selectedIndex].value)">
            <option value="请选择">请选择option>
            <option value="master">masteroption>
            <option value="slave">slaveoption>
        select>
    div>
    <div id="result">
    
    div>
    <button onclick="loadData()">加载数据button>
    <script>
        function loadData(){
            $.get("/hello",function (data){
                $("#result").html(JSON.stringify(data))
            })
        }
         function dsChange(val){
             $.post("/dsType",{dsType:val})
         }
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Code For Better 谷歌开发者之声——Flutter - Google 开源的移动 UI 框架
    LeetCode每日两题02:深搜/广搜 岛屿的最大面积 (均1200道)
    CDH大数据平台 29Cloudera Manager Console之superset之MySQL元数据配置(markdown新版三)
    vite vue3配置eslint和prettier以及sass
    Django model 联合约束和联合索引
    Python21天学习挑战赛Day(20)·selenium
    蒸散发与植被总初级生产力的区域数据下载、处理与显示
    java计算机毕业设计交通事故档案管理系统源码+数据库+系统+lw文档+mybatis+运行部署
    【稳定检索】2024年新媒体发展与语言艺术国际会议(IACNMDME 2024)
    网络安全(黑客)自学
  • 原文地址:https://blog.csdn.net/m0_46159525/article/details/126354207