使用springboot+druid双数据源动态配置操作

下面是“使用SpringBoot+Druid双数据源动态配置操作”的完整攻略及两条示例。

一、概述

在实际的项目开发中,经常会遇到同时操作多个不同的数据库的情况,比如读写分离、多租户等。使用SpringBoot+Druid双数据源动态配置操作,可以有效地解决这些问题。

二、配置SpringBoot+Druid

1. 引入相关依赖

pom.xml 文件中加入以下依赖:

<!-- SpringBoot依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MySQL驱动依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Druid连接池依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>${druid.version}</version>
</dependency>
<!-- MyBatis依赖 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>${mybatis.version}</version>
</dependency>

2. 配置Druid连接池

application.yml 文件中配置Druid连接池:

spring:
  datasource:
    # 主数据源
    druid:
      url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=UTF-8&useSSL=false
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
      initial-size: 1
      max-active: 20
      min-idle: 1
      max-wait: 60000
      time-between-eviction-runs-millis: 10000
      min-evictable-idle-time-millis: 300000
    # 辅助数据源
    druid2:
      url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=UTF-8&useSSL=false
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
      initial-size: 1
      max-active: 20
      min-idle: 1
      max-wait: 60000
      time-between-eviction-runs-millis: 10000
      min-evictable-idle-time-millis: 300000

# Druid配置
druid:
  stat-view-servlet:
    enabled: true
    url-pattern: /druid/*
    reset-enable: false
    login-username: druid
    login-password: druid
  filter:
    stat:
      log-slow-sql: true
      slow-sql-millis: 2000
      merge-sql: true
    wall:
      enabled: true
      configs:
        # 允许一次执行多条语句
        multi-statement-allow: true

# MyBatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.demo.model

3. 配置Druid监控

可以通过如下配置,开启Druid的监控:

@Configuration
public class DruidConfig {
    @Bean
    public ServletRegistrationBean statViewServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        // IP白名单设置
        servletRegistrationBean.addInitParameter("allow", "127.0.0.1");
        // IP黑名单设置
        servletRegistrationBean.addInitParameter("deny", "192.168.0.1");
        // 控制台管理用户
        servletRegistrationBean.addInitParameter("loginUsername", "druid");
        servletRegistrationBean.addInitParameter("loginPassword", "druid");
        // 是否能够重置数据
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean statFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        // IP白名单设置
        filterRegistrationBean.addInitParameter("allow", "127.0.0.1");
        // IP黑名单设置,如果allow与deny同时存在时,deny优先于allow
        filterRegistrationBean.addInitParameter("deny", "192.168.0.1");
        // 监控路径
        filterRegistrationBean.addUrlPatterns("/*");
        // 排除过滤的请求
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

三、动态配置多数据源

1. 定义数据源枚举类

public enum DataSourceEnum {
    ds1("主数据源"),
    ds2("辅助数据源");

    private String desc;

    DataSourceEnum(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
}

2. 定义动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }
}

3. 定义数据源上下文

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void set(String dbType) {
        contextHolder.set(dbType);
    }

    public static String getDataSourceKey() {
        return contextHolder.get();
    }

    public static void clear() {
        contextHolder.remove();
    }
}

4. 配置动态数据源

@Configuration
public class DataSourceConfig {
    @Bean(name = "dataSource")
    public DynamicDataSource dataSource() {
        DynamicDataSource dataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceEnum.ds1.name(), ds1());
        targetDataSources.put(DataSourceEnum.ds2.name(), ds2());
        dataSource.setTargetDataSources(targetDataSources);
        dataSource.setDefaultTargetDataSource(ds1());
        return dataSource;
    }

    @Bean(name = "ds1")
    @ConfigurationProperties(prefix = "spring.datasource.druid")
    public DataSource ds1() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "ds2")
    @ConfigurationProperties(prefix = "spring.datasource.druid2")
    public DataSource ds2() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return sessionFactory.getObject();
    }
}

5. 定义切换数据源的注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceSwitch {
    String value() default DataSourceEnum.ds1;
}

6. 定义切面切换数据源

@Aspect
@Component
public class DataSourceAspect {
    @Pointcut("@annotation(com.example.demo.datasource.DataSourceSwitch)")
    public void dataSourceSwitch() {
    }

    @Before("dataSourceSwitch() && @annotation(dataSourceSwitch)")
    public void before(JoinPoint point, DataSourceSwitch dataSourceSwitch) {
        String dataSourceKey = dataSourceSwitch.value().name();
        if (!DynamicDataSourceContextHolder.containsDataSource(dataSourceKey)) {
            System.err.println("数据源 [{}] 不存在,使用默认数据源 > {}" + dataSourceSwitch.value() + point.getSignature());
        } else {
            System.out.println("Use DataSource :{} > {}" + dataSourceSwitch.value() + point.getSignature());
            DynamicDataSourceContextHolder.setDataSourceKey(dataSourceKey);
        }
    }

    @After("dataSourceSwitch()")
    public void restoreDataSource(JoinPoint point) {
        System.out.println("Revert DataSource : {} > {}"+ DynamicDataSourceContextHolder.getDataSourceKey() + point.getSignature());
        DynamicDataSourceContextHolder.clearDataSourceKey();
    }
}

四、使用示例

1. 业务层接口

public interface UserService {
    List<User> list();

    @DataSourceSwitch(DataSourceEnum.ds2)
    List<User> listByDb2();
}

2. 业务层实现

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> list() {
        return userMapper.selectAll();
    }

    @Override
    public List<User> listByDb2() {
        return userMapper.selectAll();
    }
}

3. 控制层

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/list")
    public List<User> list() {
        return userService.list();
    }

    @GetMapping("/listByDb2")
    public List<User> listByDb2() {
        return userService.listByDb2();
    }
}

五、总结

通过上面的配置,我们可以轻松地实现动态切换数据源的功能,使用起来非常方便。当然,在实际的项目中,可能会有更为复杂的数据源操作,需要我们根据实际情况进行不同的配置和处理,但是,这里的代码可以提供我们一个很好的起点和思路。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:使用springboot+druid双数据源动态配置操作 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • SpringBoot整合BootStrap实战

    完整攻略: 创建SpringBoot项目 首先,我们需要创建一个SpringBoot项目。打开IDEA,点击“New Project”,选择Spring Initializr,填写项目信息,勾选“Web”和“Thymeleaf”作为依赖,点击“Next”,填写项目的Group和Artifact信息,点击“Finish”创建项目。 引入BootStrap依赖 …

    Java 2023年5月15日
    00
  • VScode 打造完美java开发环境最新教程

    VS Code 打造完美 Java 开发环境最新教程 Visual Studio Code 是一款免费、轻量级且功能强大的 IDE,非常适合 Java 开发人员使用。本文将介绍如何使用 VS Code 打造完美的 Java 开发环境。 安装 Java 开发环境 在 VS Code 中开发 Java 需要先安装 Java 开发环境。可以从 Oracle 官网下…

    Java 2023年5月19日
    00
  • 深入讲解Java的对象头与对象组成

    深入讲解Java的对象头与对象组成 在Java中,每个对象都有一个对象头,用来存储对象的元数据信息,同时Java对象也由对象头和实例数据两个部分组成。了解Java对象的组成可以帮助我们更好地理解Java的内存模型。 Java对象的组成 Java对象是由对象头和实例数据两个部分组成的。在64位JVM中,对象头占用16Byte,实例数据大小不定,但至少为8Byt…

    Java 2023年5月26日
    00
  • Java+MySQL实现学生信息管理系统源码

    Java+MySQL实现学生信息管理系统 本文将介绍如何使用Java和MySQL数据库实现一个简单的学生信息管理系统,并提供完整的源码和演示。 准备工作 为了使用Java和MySQL实现学生信息管理系统,需要先进行以下准备工作: 安装Java开发环境(JDK) 安装MySQL数据库 安装Java连接MySQL的驱动程序(JDBC驱动) 在这里以Windows…

    Java 2023年5月19日
    00
  • table中点击表头实现排序的功能示例介绍

    实现table中点击表头实现排序的功能是一个常见的需求,通过JavaScript和jQuery实现非常方便。下面是具体的步骤和代码示例。 1. HTML结构 首先需要在HTML中定义一个table,并将需要进行排序的数据展示在其中。其中,包括表头和表身两个部分。示例代码如下: <table id="myTable"> <…

    Java 2023年6月15日
    00
  • Java @Value(“${xxx}”)取properties时中文乱码的解决

    当我们使用Java中的注解@Value(“${xxx}”)来读取.properties配置文件中的中文值时,很容易出现中文乱码的问题。下面是针对这个问题的完整攻略。 步骤一:配置文件 首先,需要在项目中添加一个.properties配置文件,用于存放需要读取的配置属性。例如,我们可以在项目中添加一个config.properties文件,其内容如下: # 中…

    Java 2023年5月20日
    00
  • 阿里开源Java诊断工具神器使用及场景详解

    阿里开源Java诊断工具神器使用及场景详解 简介 阿里开源Java诊断工具(Arthas)是一款基于Java管理Java进程以及诊断问题的工具,它可以帮助开发人员或者运维人员快速定位问题点以及提高调试效率,广泛应用于阿里巴巴内部Java开发及O&M团队。 安装 安装前提 必须已经安装了JDK1.8+ 安装步骤 从Arthas Github官方网站ht…

    Java 2023年5月26日
    00
  • 博德之门2:加强版怎么修改存档 具体方法步骤详解

    下面是博德之门2:加强版怎么修改存档的具体方法步骤详解。 步骤一:备份存档 在进行存档修改操作之前,请先备份您的存档。这可以帮助您在修改出现问题时恢复到之前的存档状态。 步骤二:下载存档编辑器 下载名为“GIBBED.DIVINITY2.SAVEEDITO”的存档编辑器,该编辑器可以供玩家修改存档。您可以通过搜索引擎搜索并下载该编辑器。 步骤三:打开存档编辑…

    Java 2023年6月16日
    00
合作推广
合作推广
分享本页
返回顶部