中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot多數據源切換怎么實現

發布時間:2022-04-12 13:48:55 來源:億速云 閱讀:761 作者:iii 欄目:開發技術

本篇內容主要講解“SpringBoot多數據源切換怎么實現”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“SpringBoot多數據源切換怎么實現”吧!

    配置文件(YML)

    spring:
      datasource:
        default-db-key: voidme
        multi-db:
          - voidme:
              driver-class-name: com.mysql.cj.jdbc.Driver
              username: root
              password: root
              url: jdbc:mysql://192.168.42.153:3306/voidme?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useSSL=false
          - xcdef:
              driver-class-name: com.mysql.cj.jdbc.Driver
              username: root
              password: root
              url: jdbc:mysql://192.168.42.153:3306/xcdef?characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useSSL=false
    
    
    mybatis:
      #1.classpath:只會到你的classes路徑中查找找文件。
      #2.classpath*:不僅會到classes路徑,還包括jar文件中(classes路徑)進行查找。
      mapper-locations: classpath*:/mapper/**/*Mapper.xml    # mapper映射文件位置
      type-aliases-package: com.**.entity    # 實體類所在的位置
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #用于控制臺打印sql語句
        map-underscore-to-camel-case: true #開啟將帶有下劃線的表字段 映射為駝峰格式的實體類屬性

    核心代碼

    SpringBoot多數據源切換怎么實現

    DynamicDataSource

    這個類用于獲取數據源的(核心)

    package com.dynamicdatadource.dynamic;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Value("${spring.datasource.default-db-key}")
        private String defaultDbKey;
    
        @Override
        protected Object determineCurrentLookupKey() {
            String currentDb = DynamicDataSourceService.currentDb();
            if (currentDb == null) {
                return defaultDbKey;
            }
            return currentDb;
        }
    }

    DynamicDataSourceService

    這個類是數據源切換工具,我們做了線程隔離了所以不用擔心多線程數據源會混亂的問題

    package com.dynamicdatadource.dynamic;
    
    import com.application.ApplicationContextProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    public class DynamicDataSourceService  {
        private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceService.class);
    
        private static final Map<Object, Object> dataSources = new HashMap<>();
        private static final ThreadLocal<String> dbKeys = ThreadLocal.withInitial(() -> null);
    
        /**
         * 動態添加一個數據源
         *
         * @param name       數據源的key
         * @param dataSource 數據源對象
         */
        public static void addDataSource(String name, DataSource dataSource) {
            DynamicDataSource dynamicDataSource = ApplicationContextProvider.getApplicationContext().getBean(DynamicDataSource.class);
            dataSources.put(name, dataSource);
            dynamicDataSource.setTargetDataSources(dataSources);
            dynamicDataSource.afterPropertiesSet();
            log.info("添加了數據源:{}",name);
        }
    
        /**
         * @param name   數據源的key
         * @param driverClassName  驅動
         * @param url     數據庫連接地址
         * @param username   數據庫賬戶
         * @param password   數據庫密碼
         */
        public static void addDataSource(String name, String driverClassName,String url,String username,String password) {
            DataSourceBuilder<?> builder = DataSourceBuilder.create();
            builder.driverClassName(driverClassName);
            builder.username(username);
            builder.password(password);
            builder.url(url);
            addDataSource(name,builder.build());
            log.info("添加了數據源:{}",name);
        }
        /**
         * 切換數據源
         */
        public static void switchDb(String dbKey) {
            dbKeys.set(dbKey);
        }
    
        /**
         * 重置數據源(切換為默認的數據源)
         */
        public static void resetDb() {
            dbKeys.remove();
        }
    
        /**
         * 獲取當前數據源的key
         */
        public static String currentDb() {
            return dbKeys.get();
        }
    }

    DynamicDataSourceConfig

    將數據源配置到springboot中和初始化Mybaitis配置

    package com.dynamicdatadource.dynamic;
    
    import lombok.Data;
    import org.apache.ibatis.logging.Log;
    import org.mybatis.spring.SqlSessionFactoryBean;
    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 org.springframework.transaction.PlatformTransactionManager;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    @Configuration
    @ConfigurationProperties(prefix = "mybatis")
    @Data
    public class DynamicDataSourceConfig {
    
        private String mapperLocations;
        private String typeAliasesPackage;
        @Data
        public class MybatisConfiguration{
            private String logImpl;
            private boolean mapUnderscoreToCamelCase;
        }
        private  MybatisConfiguration configuration=new MybatisConfiguration();
    
    
        /**
         * 動態數據源
         */
        @Bean
        public DynamicDataSource dynamicDataSource() {
            DynamicDataSource dataSource = new DynamicDataSource();
            Map<Object, Object> targetDataSources = new HashMap<>();
            dataSource.setTargetDataSources(targetDataSources);
            return dataSource;
        }
    
        /**
         * 會話工廠Mybaitis
         */
        @Bean
        public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException, ClassNotFoundException {
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setMapUnderscoreToCamelCase(this.configuration.isMapUnderscoreToCamelCase()); //開啟駝峰命名
            configuration.setLogImpl((Class<? extends Log>) Class.forName(this.configuration.getLogImpl())); //控制臺打印sql日志
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(dynamicDataSource());
            sqlSessionFactoryBean.setConfiguration(configuration);
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations));
            sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
            return sqlSessionFactoryBean;
        }
    
        /**
         * 事務管理器
         */
        @Bean
        public PlatformTransactionManager transactionManager() {
            return new DataSourceTransactionManager(dynamicDataSource());
        }
    }

    加載YML數據庫配置類

    package com.dynamicdatadource.config;
    
    import com.dynamicdatadource.dynamic.DynamicDataSourceService;
    import lombok.Data;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.sql.DataSource;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    @Component
    @Data
    @ConfigurationProperties(prefix = "spring.datasource")
    public class YmlDataSourceProvider  {
    
        private List<Map<String, DataSourceProperties>> multiDb;
    
        private DataSource buildDataSource(DataSourceProperties prop) {
            DataSourceBuilder<?> builder = DataSourceBuilder.create();
            builder.driverClassName(prop.getDriverClassName());
            builder.username(prop.getUsername());
            builder.password(prop.getPassword());
            builder.url(prop.getUrl());
            return builder.build();
        }
    
        public void initDataSource() {
            multiDb.forEach(map -> {
                Set<String> keys = map.keySet();
                keys.forEach(key -> {
                    DataSourceProperties properties = map.get(key);
                    DataSource dataSource = buildDataSource(properties);
                    DynamicDataSourceService.addDataSource(key, dataSource);
                });
            });
        }
    
        //在構造函數之后執行
        @PostConstruct
        public void init() {
            initDataSource();
        }
    }

    aop切換

    package com.dynamicdatadource.aop;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD,ElementType.TYPE})//作用:方法和類
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DynamicDataSourceAnno {
        String key() default "";
    }
    package com.dynamicdatadource.aop;
    import com.dynamicdatadource.dynamic.DynamicDataSourceService;
    import org.apache.commons.lang.StringUtils;
    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.springframework.stereotype.Component;
    
    // 用于單獨的請求或者類進行切換數據庫
    @Aspect
    @Component
    public class DynamicDataSourceAspect {
        @Pointcut("@annotation(com.dynamicdatadource.aop.DynamicDataSourceAnno)")
        public void dynamicDataSourceAnno() {
        }
    
        @Around("dynamicDataSourceAnno()")
        public Object DynamicDataSourceAspectAroundAnno(ProceedingJoinPoint joinPoint) {
            Object object = null;
            try {
                MethodSignature signature = (MethodSignature)joinPoint.getSignature();
                DynamicDataSourceAnno dynamicDataSourceAnno  = signature.getMethod().getAnnotation(DynamicDataSourceAnno.class);
                String key = dynamicDataSourceAnno.key();
                if (StringUtils.isNotBlank(key)) {
                    //切換為指定數據庫
                    DynamicDataSourceService.switchDb(key);
                }
                object = joinPoint.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }finally {
                //還原為默認配置
                DynamicDataSourceService.resetDb();
            }
            return object;
        }
        // 還可以擴展包路徑切換
    }

    效果

    運行程序之后,就會將數據源加入到數據源列表中了

    SpringBoot多數據源切換怎么實現

    擴展

    MysqlDataSourceInitialize

    從數據庫中將配置信息查詢出來,然后動態添加到數據源列表中

    package com.dao.config;
    
    import com.dao.DatasourceDao;
    import com.dynamicdatadource.aop.DynamicDataSourceAnno;
    import com.dynamicdatadource.dynamic.DynamicDataSourceService;
    import com.entity.DataSourceEneity;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.sql.DataSource;
    import java.util.List;
    
    //從數據庫中查詢出全部的數據源,添加到數據源容器中
    
    /**
     * 表結構如下:
     *
     * CREATE TABLE `t_datasource` (
     *   `id` int(11) NOT NULL,
     *   `key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '綁定的key,用于數據源的切換',
     *   `url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '數據庫連接地址',
     *   `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '數據庫用戶名',
     *   `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '數據庫密碼',
     *   `driverClassName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '數據庫驅動',
     *   `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '數據庫類型:  mysql ,oracle,..',
     *   `state` int(2) NOT NULL COMMENT '是否可用: 1可用 ,2不可用',
     *   PRIMARY KEY (`id`),
     *   UNIQUE KEY `key` (`key`)
     * ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
     *
     * 上表要放入到默認數據源中的數據庫里才行
     */
    @Component
    public class MysqlDataSourceInitialize implements ApplicationRunner  {
    
        @Autowired
        private DatasourceDao datasourceDao;
    
        //項目啟動后執行初始化數據源
        @Override
        public void run(ApplicationArguments args) throws Exception {
            try {
                List<DataSourceEneity> dataSources = datasourceDao.getDataSources();
                for (DataSourceEneity dataSource : dataSources) {
                    DynamicDataSourceService.addDataSource(dataSource.getKey(),dataSource.getDataSource());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    DataSourceEneity實體類

    @Data
    public class DataSourceEneity {
        private int id;
        private String key;
        private String url;
        private String username;
        private String password;
        private String driverClassName;
        private String type;
        private int state;
    
        public  DataSource getDataSource() {
            DataSourceBuilder<?> builder = DataSourceBuilder.create();
            builder.driverClassName(driverClassName);
            builder.username(username);
            builder.password(password);
            builder.url(url);
            return  builder.build();
        }
    }

    到此,相信大家對“SpringBoot多數據源切換怎么實現”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    汨罗市| 西丰县| 潞城市| 安龙县| 左云县| 营口市| 河津市| 辛集市| 仲巴县| 新余市| 赤峰市| 娄底市| 清原| 利川市| 岳普湖县| 长沙市| 大名县| 信宜市| 英超| 柳林县| 郁南县| 伊宁县| 青田县| 湄潭县| 新竹县| 探索| 循化| 萍乡市| 东至县| 义乌市| 闽侯县| 汾西县| 清原| 重庆市| 迭部县| 古蔺县| 浦城县| 宜兰市| 肥城市| 韩城市| 诏安县|