Spring Boot集成Druid实现多数据源的两种方式

这篇具有很好参考价值的文章主要介绍了Spring Boot集成Druid实现多数据源的两种方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

项目场景:

一、集成com.baomidou的方式

1、maven依赖:

2、 配置文件:

3、 使用注解切换数据源: 

二、基于AOP手动实现多数据源原生的方式

1、maven依赖:

2、 配置文件:

3、 多数据源名称类

4、自定义注解 

5、配置类

6、动态数据源配置

 7、AOP切面拦截注解

8、Dao层,跟正常一样的

 9、service层,加上多数据源注解

 10、Controller测试

三、结果展示


项目场景:

Spring Boot集成Druid实现多数据源的两种方式:

1、集成com.baomidou,引入dynamic-datasource依赖;

2、原生的方式,基于AOP手动实现多数据源;


一、集成com.baomidou的方式

1、maven依赖:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

2、 配置文件:

1.spring.datasource.dynamic前缀,是baomidou源码里固定的;

2.first、second是自定义的名称,可以更改;

# 多数据源配置,默认master
spring.datasource.dynamic.primary = first
# 数据源1
spring.datasource.dynamic.datasource.first.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.first.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.dynamic.datasource.first.url = jdbc:mysql://127.0.0.1:3306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.dynamic.datasource.first.username = test
spring.datasource.dynamic.datasource.first.password = test1
# 数据源2
spring.datasource.dynamic.datasource.second.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.second.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.dynamic.datasource.second.url = jdbc:mysql://127.0.0.1:18306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.dynamic.datasource.second.username = test
spring.datasource.dynamic.datasource.second.password = test1

# druid多数据源全局配置
spring.datasource.dynamic.druid.filter.stat.log-slow-sql = true
spring.datasource.dynamic.druid.filter.stat.slow-sql-millis = 1000
spring.datasource.dynamic.druid.min-evictable-idle-time-millis = 300000
spring.datasource.dynamic.druid.test-on-borrow = false
spring.datasource.dynamic.druid.filter.stat.merge-sql = false
spring.datasource.dynamic.druid.test-on-return = false
spring.datasource.dynamic.druid.initial-size = 10
spring.datasource.dynamic.druid.min-idle = 10
spring.datasource.dynamic.druid.max-wait = 60000
spring.datasource.dynamic.druid.pool-prepared-statements = true
spring.datasource.dynamic.druid.test-while-idle = true
spring.datasource.dynamic.druid.validation-query = select 1
spring.datasource.dynamic.druid.filter.wall.config.multi-statement-allow = true
spring.datasource.dynamic.druid.time-between-eviction-runs-millis = 60000
spring.datasource.dynamic.druid.max-pool-prepared-statement-per-connection-size = 20
spring.datasource.dynamic.druid.max-active = 100
# druid监控全局配置
spring.datasource.druid.stat-view-servlet.enabled = true
spring.datasource.druid.stat-view-servlet.url-pattern = /druid/*

验证配置文件是否生效:Spring Boot集成Druid查看配置是否生效_涛哥是个大帅比的博客-CSDN博客 

3、 使用注解切换数据源: 

@DS注解说明:

1.注解在方法上、类上、接口、枚举,同时存在就近原则,方法上注解优先于类上注解;

2.不使用@DS注解,默认主数据源;

类上:

@DS("db2")
public class test(){}

 方法上:

@DS("db2")
public void test(){}

mapper方法上

@Select("SELECT * FROM TEST WHERE A = #{A}")
@DS("db2")
Map<String, Object> test(@Param("A") String A);

多数据源可能会碰到事务问题:
 Spring Boot多数据源事务@DSTransactional的使用_涛哥是个大帅比的博客-CSDN博客


二、基于AOP手动实现多数据源原生的方式

1、maven依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

2、 配置文件:

1.Spring Boot 2.X 版本不再支持配置继承,多数据源的话每个数据源的所有配置都需要单独配置,否则配置不会生效;

2.first、second是自定义的名称,对应DynamicDataSourceConfig配置类,可以更改;

# 多数据源配置
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
# 数据源1
spring.datasource.druid.first.name = first
spring.datasource.druid.first.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.druid.first.url = jdbc:mysql://127.0.0.1:3306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.first.username = test
spring.datasource.druid.first.password = test1
# 数据源2
spring.datasource.druid.second.name = second
spring.datasource.druid.second.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.druid.second.url = jdbc:mysql://127.0.0.1:18306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.second.username = test
spring.datasource.druid.second.password = test1

# druid数据源1
spring.datasource.druid.first.filter.stat.log-slow-sql = true
spring.datasource.druid.first.filter.stat.slow-sql-millis = 1000
spring.datasource.druid.first.min-evictable-idle-time-millis = 300000
spring.datasource.druid.test-on-borrow = false
spring.datasource.druid.first.filter.stat.merge-sql = false
spring.datasource.druid.test-on-return = false
spring.datasource.druid.first.initial-size = 10
spring.datasource.druid.first.min-idle = 10
spring.datasource.druid.first.max-wait = 60000
spring.datasource.druid.first.pool-prepared-statements = true
spring.datasource.druid.first.test-while-idle = true
spring.datasource.druid.first.validation-query = select 1
spring.datasource.druid.first.filter.wall.config.multi-statement-allow = true
spring.datasource.druid.first.time-between-eviction-runs-millis = 60000
spring.datasource.druid.first.max-pool-prepared-statement-per-connection-size = 20
spring.datasource.druid.first.max-active = 100
# druid数据源2
spring.datasource.druid.second.filter.stat.log-slow-sql = true
spring.datasource.druid.second.filter.stat.slow-sql-millis = 1000
spring.datasource.druid.second.min-evictable-idle-time-millis = 300000
spring.datasource.druid.second.test-on-borrow = false
spring.datasource.druid.second.filter.stat.merge-sql = false
spring.datasource.druid.second.test-on-return = false
spring.datasource.druid.second.initial-size = 10
spring.datasource.druid.second.min-idle = 10
spring.datasource.druid.second.max-wait = 60000
spring.datasource.druid.second.pool-prepared-statements = true
spring.datasource.druid.second.test-while-idle = true
spring.datasource.druid.second.validation-query = select 1
spring.datasource.druid.second.filter.wall.config.multi-statement-allow = true
spring.datasource.druid.second.time-between-eviction-runs-millis = 60000
spring.datasource.druid.second.max-pool-prepared-statement-per-connection-size = 20
spring.datasource.druid.second.max-active = 100
# druid监控全局配置
spring.datasource.druid.stat-view-servlet.enabled = true
spring.datasource.druid.stat-view-servlet.url-pattern = /druid/*

验证配置文件是否生效:Spring Boot集成Druid查看配置是否生效_涛哥是个大帅比的博客-CSDN博客 

3、 多数据源名称类

package com.test.datasources;

/**
 * 增加多数据源,在此配置
 */
public interface DataSourceNames {
    String FIRST = "first";
    String SECOND = "second";

} 

4、自定义注解 

package com.test.datasources.annotation;

import java.lang.annotation.Documented;
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)
@Documented
public @interface DataSource {
    String value() default "";
}

5、配置类

package com.test.datasources;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

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 org.springframework.jdbc.core.JdbcTemplate;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;

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

    @Bean
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource secondDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate() {
     return new JdbcTemplate(firstDataSource());
    }
}

6、动态数据源配置

package com.test.datasources;

import java.util.Map;

import javax.sql.DataSource;

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

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

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(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();
    }

}

 7、AOP切面拦截注解

package com.test.datasources.aspect;

import java.lang.reflect.Method;

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import com.test.datasources.DataSourceNames;
import com.test.datasources.DynamicDataSource;
import com.test.datasources.annotation.DataSource;

/**
 * 多数据源,切面处理类
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    /*
     * @annotation匹配指定注解的方法
     * @within匹配指定注解的类
     * 注意:这里只拦截所注解的类,如果调用的是父类的方法,那么不会拦截,除非父类方法在子类中被覆盖。
     */
    @Pointcut("@annotation(com.test.datasources.annotation.DataSource) || @within(com.test.datasources.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> dataClass = Class.forName(signature.getDeclaringTypeName());
        
        DataSource dsMethod = method.getAnnotation(DataSource.class);
        DataSource dsClass = dataClass.getAnnotation(DataSource.class);
        if(dsMethod != null){
        	//方法优先,如果方法上存在注解,则优先使用方法上的注解
        	DynamicDataSource.setDataSource(dsMethod.value());
            logger.debug("set datasource is " + dsMethod.value());
        }else if(dsClass != null){
            //其次类优先,如果类上存在注解,则使用类上的注解
        	DynamicDataSource.setDataSource(dsClass.value());
            logger.debug("set datasource is " + dsClass.value());
        }else{
        	//如果都不存在,则使用默认
        	DynamicDataSource.setDataSource(DataSourceNames.FIRST);
            logger.debug("set datasource is " + DataSourceNames.FIRST);
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

8、Dao层,跟正常一样的

package com.test.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import com.test.entity.Test1Entity;

@Mapper
public interface Test1Dao {
	
	@Select("select * from test1")
	Test1Entity getById(@Param("id")Integer id);
}
package com.test.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import com.test.entity.Test2Entity;

@Mapper
public interface Test2Dao {
	@Select("select * from test2")
	Test2Entity getById(@Param("id")Integer id);
}

 9、service层,加上多数据源注解

package com.test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.test.datasources.DataSourceNames;
import com.test.datasources.annotation.DataSource;
import com.test.entity.Test1Entity;
import com.test.mapper.Test1Dao;

@Service
@DataSource(DataSourceNames.FIRST)
public class Test1Service {

	@Autowired
	private Test1Dao test1Dao;
	
	public Test1Entity getById(int id) {
		return test1Dao.getById(id);
	}
}
package com.test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.test.datasources.DataSourceNames;
import com.test.datasources.annotation.DataSource;
import com.test.entity.Test2Entity;
import com.test.mapper.Test2Dao;

@Service
@DataSource(DataSourceNames.SECOND)
public class Test2Service  {

	@Autowired
	private Test2Dao test2Dao;
	
	public Test2Entity getById(int id) {
		return test2Dao.getById(id);
	}
}

 10、Controller测试

package com.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.test.entity.Test1Entity;
import com.test.entity.Test2Entity;
import com.test.service.Test1Service;
import com.test.service.Test2Service;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 动态数据源测试
 */
@Api(tags = "动态数据源测试")
@RestController
@RequestMapping("/test")
public class DynamicController {

	@Autowired
	private Test1Service test1Service;
	@Autowired
	private Test2Service test2Service;
	
	@ApiOperation(value = "数据源1")
	@RequestMapping(value = "/test1", method = RequestMethod.GET)
	public String test1() {
		Test1Entity entity = test1Service.getById(1);
		return entity.getName();
	}
	
	@ApiOperation(value = "数据源2")
	@RequestMapping(value = "/test2", method = RequestMethod.GET)
	public String test2() {
		Test2Entity entity = test2Service.getById(2);
		return entity.getName();
	}
}

多数据源可能会碰到事务问题:https://blog.csdn.net/u011974797/article/details/130154340

三、结果展示

服务启动会打印日志:

com.alibaba.druid.pool.DruidDataSource   : {dataSource-1,first} inited
com.alibaba.druid.pool.DruidDataSource   : {dataSource-2,second} inited

druid监控页面:

Spring Boot集成Druid实现多数据源的两种方式

 Spring Boot集成Druid实现多数据源的两种方式

源码地址:https://download.csdn.net/download/u011974797/87680942文章来源地址https://www.toymoban.com/news/detail-492957.html

到了这里,关于Spring Boot集成Druid实现多数据源的两种方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot实现多数据源配置(Druid/Hikari)

    使用springboot+mybatis-plus+(Druid/Hikari)实现多数据源配置 操作步骤: 引入相应的maven坐标 编写mybatis配置,集成mybatis或mybatis-plus(如果已集成可跳过) 编写数据源配置类 编写注解,并通过aop进行增强(编写数据源切换代码) 类或方法中使用注解,对数据源进行切换 第一步:

    2024年02月13日
    浏览(49)
  • Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换

    MySQL 主从复制是一种常见的数据库架构,它可以提高数据库的性能和可用性。 动态数据源切换则可以根据业务需求,在不同场景下使用不同的数据源,比如在读多写少的场景下,可以通过切换到从库来分担主库的压力 。 在本文中,我们将介绍如何在 Spring Boot 中实现 MySQL 动

    2024年02月19日
    浏览(59)
  • 【Spring Boot 3】【数据源】自定义多数据源

    软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时

    2024年02月01日
    浏览(60)
  • SpringBoot整合Mybatis-Plus+Druid实现多数据源

    🌺本文主要讲解 springboot +mybatisplus + druid 实现多数据源配置功能 🌺 主页传送门:📀 传送 Spring Boot:    Spring Boot是一个基于Spring框架的开源Java开发框架,旨在简化Spring应用程序的开发、配置和部署。它提供了一种快速、敏捷的方式来构建独立的、生产级别的Spring应用程

    2024年02月09日
    浏览(102)
  • 【Spring Boot 3】【数据源】自定义JPA数据源

    软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时

    2024年01月21日
    浏览(69)
  • 【Spring Boot】Spring Boot整合多数据源

    在实际的开发工作中,我们经常会遇到需要整合多个数据源的情况,比如同时连接多个数据库、读写分离、跨数据库查询等。本文将介绍如何使用Spring Boot来实现多数据源的整合,对于刚刚接触开发的小伙伴可能有一些帮助。 在一个应用程序中使用多个数据源意味着我们需要

    2024年02月10日
    浏览(42)
  • 【Spring Boot 3】【数据源】自定义JDBC多数据源

    软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时

    2024年01月23日
    浏览(49)
  • 【Spring Boot 3】【数据源】自定义JPA多数据源

    软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时

    2024年01月22日
    浏览(80)
  • Spring Boot 配置双数据源

    Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive. happy for hardess to solve denpendies. 需求: 1.基本步骤 添加依赖 添加 Spring Boot 和数据库驱动的依赖 配置数据源 在 application.properties 或 application.yml 中分别配

    2024年01月22日
    浏览(61)
  • 实例讲解Spring boot动态切换数据源

    摘要: 本文模拟一下在主库查询订单信息查询不到的时候,切换数据源去历史库里面查询。 本文分享自华为云社区《springboot动态切换数据源》,作者:小陈没烦恼 。 在公司的系统里,由于数据量较大,所以配置了多个数据源,它会根据用户所在的地区去查询那一个数据库

    2024年02月06日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包