文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringBoot自定义动态切换数据源的方法是什么

2023-06-21 22:22

关注

本篇内容主要讲解“SpringBoot自定义动态切换数据源的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot自定义动态切换数据源的方法是什么”吧!

1、添加maven依赖

<dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <scope>runtime</scope>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid</artifactId>            <version>1.1.3</version>        </dependency>        <!--properties动态注入-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-configuration-processor</artifactId>            <optional>true</optional>        </dependency>        <!--springBoot的aop-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-aop</artifactId>        </dependency>

2、配置application.yml

# 数据库访问配置# 主数据源,默认的druid:  datasource:    type: com.alibaba.druid.pool.DruidDataSource    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://192.168.1.113:3306/test?useUnicode=true&characterEncoding=utf-8    username: root    password: root    # 下面为连接池的补充设置,应用到上面所有数据源中    # 初始化大小,最小,最大    initialSize: 5    minIdle: 5    maxActive: 20    # 配置获取连接等待超时的时间    maxWait: 60000    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒    timeBetweenEvictionRunsMillis: 60000    # 配置一个连接在池中最小生存的时间,单位是毫秒    minEvictableIdleTimeMillis: 300000    validationQuery: SELECT 1 FROM DUAL    testWhileIdle: true    testOnBorrow: false    testOnReturn: false    # 打开PSCache,并且指定每个连接上PSCache的大小    poolPreparedStatements: true    maxPoolPreparedStatementPerConnectionSize: 20    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙    filters: stat,wall,log4j    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录    connectionProperties:      druid:        stat:          mergeSql: true          slowSqlMillis: 5000    # 合并多个DruidDataSource的监控数据#多数据源mysql-db:  datasource:    names: logic,dao    logic:      driver-class-name: com.mysql.jdbc.Driver      url: jdbc:mysql://192.168.1.113:3306/test1?useUnicode=true&characterEncoding=utf-8      username: root      password: root    dao:      driver-class-name: com.mysql.jdbc.Driver      url: jdbc:mysql://192.168.1.113:3306/test2?useUnicode=true&characterEncoding=utf-8      username: root      password: root

3、配置动态数据源

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicDataSource extends AbstractRoutingDataSource {    @Override    protected Object determineCurrentLookupKey() {        return DataSourceHolder.getDataSource();    }}

4、配置数据源操作Holder

import java.util.ArrayList;import java.util.List;public class DataSourceHolder {    //线程本地环境    private static final ThreadLocal<String> contextHolders = new ThreadLocal<String>();    //数据源列表    public static List<String> dataSourceIds = new ArrayList<>();    //设置数据源    public static void setDataSource(String customerType) {        contextHolders.set(customerType);    }    //获取数据源    public static String getDataSource() {        return (String) contextHolders.get();    }    //清除数据源    public static void clearDataSource() {        contextHolders.remove();    }        public static boolean containsDataSource(String dataSourceId){        return dataSourceIds.contains(dataSourceId);    }}

5、读取自定义数据源,并配置

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.MutablePropertyValues;import org.springframework.beans.PropertyValues;import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;import org.springframework.boot.bind.RelaxedDataBinder;import org.springframework.boot.bind.RelaxedPropertyResolver;import org.springframework.context.EnvironmentAware;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.convert.ConversionService;import org.springframework.core.convert.support.DefaultConversionService;import org.springframework.core.env.Environment;import org.springframework.stereotype.Component;import javax.sql.DataSource;import java.util.HashMap;import java.util.Map;@Component@Configurationpublic class DynamicDataSourceConfig implements EnvironmentAware {    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceConfig.class);    // 默认数据源    private DataSource defaultDataSource;    // 属性值    private PropertyValues dataSourcePropertyValues;    // 如配置文件中未指定数据源类型,使用该默认值    private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";    private ConversionService conversionService = new DefaultConversionService();    private Map<String, DataSource> customDataSources = new HashMap<>();    @Override    public void setEnvironment(Environment environment) {        initDefaultDatasource(environment);        initOtherDatasource(environment);    }    private void initOtherDatasource(Environment environment) {        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "mysql-db.datasource.");        String dsPrefixs = propertyResolver.getProperty("names");        for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源            Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix+".");            DataSource ds = buildDataSource(dsMap);            customDataSources.put(dsPrefix, ds);            dataBinder(ds, environment);        }    }    private void initDefaultDatasource(Environment environment) {        // 读取主数据源        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "druid.datasource.");        Map<String, Object> dsMap = new HashMap<>();        dsMap.put("type", propertyResolver.getProperty("type"));        dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));        dsMap.put("url", propertyResolver.getProperty("url"));        dsMap.put("username", propertyResolver.getProperty("username"));        dsMap.put("password", propertyResolver.getProperty("password"));        defaultDataSource = buildDataSource(dsMap);        DataSourceHolder.dataSourceIds.add("ds1");        dataBinder(defaultDataSource, environment);    }        @SuppressWarnings("unchecked")    public DataSource buildDataSource(Map<String, Object> dsMap) {        try {            Object type = dsMap.get("type");            if (type == null)                type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource            Class<? extends DataSource> dataSourceType;            dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);            String driverClassName = dsMap.get("driver-class-name").toString();            String url = dsMap.get("url").toString();            String username = dsMap.get("username").toString();            String password = dsMap.get("password").toString();            DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)                    .username(username).password(password).type(dataSourceType);            return factory.build();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return null;    }        private void dataBinder(DataSource dataSource, Environment env){        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);        //dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));        dataBinder.setConversionService(conversionService);        dataBinder.setIgnoreNestedProperties(false);//false        dataBinder.setIgnoreInvalidFields(false);//false        dataBinder.setIgnoreUnknownFields(true);//true        if(dataSourcePropertyValues == null){            Map<String, Object> rpr = new RelaxedPropertyResolver(env, "druid.datasource.").getSubProperties(".");            Map<String, Object> values = new HashMap<>(rpr);            // 排除已经设置的属性            values.remove("type");            values.remove("driver-class-name");            values.remove("url");            values.remove("username");            values.remove("password");            dataSourcePropertyValues = new MutablePropertyValues(values);        }        dataBinder.bind(dataSourcePropertyValues);    }    @Bean(name = "dataSource")    public DynamicDataSource dataSource() {        DynamicDataSource dynamicDataSource = new DynamicDataSource();        // 默认数据源        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);        // 配置多数据源        Map<Object, Object> dsMap = new HashMap(5);        dsMap.put("ds1", defaultDataSource);        dsMap.putAll(customDataSources);        for (String key : customDataSources.keySet())            DataSourceHolder.dataSourceIds.add(key);        dynamicDataSource.setTargetDataSources(dsMap);        return dynamicDataSource;    }}

6、动态切换关键——AOP进行切换

@Retention(RetentionPolicy.RUNTIME)@Target({        ElementType.METHOD})public @interface DS {    String name() default "ds1";}
import com.chen.config.dynamicDS.DataSourceHolder;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.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;@Aspect@Order(-1)// 保证该AOP在@Transactional之前执行@Componentpublic class DynamicDataSourceAspect {    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);    @Before("@annotation(ds)")    public void changeDataSource(JoinPoint point, DS ds) throws Throwable {        String dsId = ds.name();        if (!DataSourceHolder.containsDataSource(dsId)) {            logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature());        } else {            logger.debug("Use DataSource : {} > {}", ds.name(), point.getSignature());            DataSourceHolder.setDataSource(ds.name());        }    }    @After("@annotation(ds)")    public void restoreDataSource(JoinPoint point, DS ds) {        logger.debug("Revert DataSource : {} > {}", ds.name(), point.getSignature());        DataSourceHolder.clearDataSource();    }}

7、使用

1)、配置mapper

public interface DynamicDSMapper {    Integer queryJournal();    String queryUser();    String queryType();}
<?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.chen.mapper.DynamicDSMapper">    <select id="queryJournal" resultType="java.lang.Integer">        SELECT uid FROM journal    </select>    <select id="queryUser" resultType="java.lang.String">        SELECT name FROM user    </select>    <select id="queryType" resultType="java.lang.String">        SELECT parent FROM p_type    </select></mapper>

2)、配置service

@Servicepublic class DynamicServciceImpl implements DynamicServcice {    @Autowired    private DynamicDSMapper dynamicDSMapper;    @DS()    public Integer ds1() {        return dynamicDSMapper.queryJournal();    }    @DS(name = "logic")    public String ds2() {        return dynamicDSMapper.queryUser();    }    @DS(name = "dao")    public String ds3() {        return dynamicDSMapper.queryType();    }}

3)、单元测试调用

@RunWith(SpringRunner.class)@SpringBootTestpublic class TestDynamicDS {    private Logger logger = LoggerFactory.getLogger(TestDynamicDS.class);//    @Autowired    private DynamicServcice dynamicServcice;    @Test    public void test() {//        Integer integer = dynamicServcice.ds1();//        logger.info("integer:"+integer);//        String ds2 = dynamicServcice.ds2();//        logger.info("ds2:"+ds2);        String ds3 = dynamicServcice.ds3();        logger.info("ds3:"+ds3);    }}

4)、测试结果

SpringBoot自定义动态切换数据源的方法是什么

到此,相信大家对“SpringBoot自定义动态切换数据源的方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯