前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Boot2.x 动态数据源配置

Spring Boot2.x 动态数据源配置

原创
作者头像
壹言
修改2020-03-02 07:43:54
1.3K0
修改2020-03-02 07:43:54
举报
文章被收录于专栏:WorldhelloWorldhello

原文链接:Spring Boot2.x 动态数据源配置

基于 Spring Boot 2.x、Spring Data JPA、druid、mysql 的动态数据源配置Demo,适合用于数据库的读写分离等应用场景。通过在Service层方法上添加自定义注解实现读写不同的数据库。

配置文件已配置好druid监控相关属性,监控页面链接:ip:8080/druid。账号:admin,密码:123456。详情查看 application.yml 文件。

配置 pom.xml 文件
代码语言:javascript
复制
      <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
配置application.yml文件
代码语言:javascript
复制
spring:
  datasource:
    druid:
      primary:
        driverClassName: com.mysql.cj.jdbc.Driver
        username: root
        password: root
        url: jdbc:mysql://localhost:3306/primary?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
        filters: stat,wall
      local:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: root
        url: jdbc:mysql://localhost:3306/local?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
        filters: stat,wall
      stat-view-servlet:
        enabled: true
        login-username: admin
        login-password: 123456
        reset-enable: false
        url-pattern: /druid/*
      web-stat-filter:
        enabled: true
        # 添加过滤规则
        url-pattern: /*
        # 忽略过滤格式
        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
  jpa:
    database: MYSQL
    hibernate:
      show_sql: true
      format_sql: true
      primary-dialect: org.hibernate.dialect.MySQL5InnoDBDialect
      secondary-dialect: org.hibernate.dialect.MySQL5InnoDBDialect
      # 打开后会自动在主库生成表
      # ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    # 打开后会自动在主库生成表
    # generate-ddl: true
项目目录结构

目录结构

DataSource.java
代码语言:javascript
复制
package dynamic.data.annotation;

import dynamic.data.common.ContextConst;

import java.lang.annotation.*;
/**
 * @Author: ChangXuan
 * @Decription:
 * @Date: 22:25 2020/2/23
 **/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    ContextConst.DataSourceType value() default ContextConst.DataSourceType.PRIMARY;
}
DynamicDataSourceAspect.java
代码语言:javascript
复制
package dynamic.data.aspect;

import dynamic.data.common.ContextConst;
import dynamic.data.datasource.DataSourceContextHolder;
import dynamic.data.annotation.DataSource;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
/**
 * @Author: ChangXuan
 * @Decription:
 * @Date: 22:28 2020/2/23
 **/
@Component
@Aspect
public class DynamicDataSourceAspect {
    @Before("execution(* dynamic.data.service..*.*(..))")
    public void before(JoinPoint point){
        try {
            DataSource annotationOfClass = point.getTarget().getClass().getAnnotation(DataSource.class);
            String methodName = point.getSignature().getName();
            Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
            Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes);
            DataSource methodAnnotation = method.getAnnotation(DataSource.class);
            methodAnnotation = methodAnnotation == null ? annotationOfClass:methodAnnotation;
            ContextConst.DataSourceType dataSourceType = methodAnnotation != null && methodAnnotation.value() !=null ? methodAnnotation.value() :ContextConst.DataSourceType.PRIMARY ;
            DataSourceContextHolder.setDataSource(dataSourceType.name());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    @After("execution(* dynamic.data.service..*.*(..))")
    public void after(JoinPoint point){
        DataSourceContextHolder.clearDataSource();
    }
}
ContextConst.java
代码语言:javascript
复制
package dynamic.data.common;

/**
 * @Author: ChangXuan
 * @Decription:
 * @Date: 22:17 2020/2/23
 **/
public interface ContextConst {
    enum DataSourceType{
        PRIMARY,LOCAL
    }
}
DataSourceContextHolder .java
代码语言:javascript
复制
package dynamic.data.datasource;

/**
 * @Author: ChangXuan
 * @Decription:
 * @Date: 22:23 2020/2/23
 **/
public class DataSourceContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDataSource(String dbType){
        System.out.println("切换到["+dbType+"]数据源");
        contextHolder.set(dbType);
    }

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

    public static void clearDataSource(){
        contextHolder.remove();
    }
}
DynamicDataSource.java
代码语言:javascript
复制
package dynamic.data.datasource;

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

/**
 * @Author: ChangXuan
 * @Decription:
 * @Date: 22:22 2020/2/23
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}
MutiplyDataSource.java
代码语言:javascript
复制
package dynamic.data.datasource;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import dynamic.data.common.ContextConst;
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.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
/**
 * @Author: ChangXuan
 * @Decription:
 * @Date: 22:15 2020/2/23
 **/
@Configuration
public class MutiplyDataSource {
    @Bean(name = "dataSourcePrimary")
    @ConfigurationProperties(prefix = "spring.datasource.druid.primary")
    public DataSource primaryDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

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

    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //配置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(primaryDataSource());

        //配置多数据源
        HashMap<Object, Object> dataSourceMap = new HashMap();
        dataSourceMap.put(ContextConst.DataSourceType.PRIMARY.name(),primaryDataSource());
        dataSourceMap.put(ContextConst.DataSourceType.LOCAL.name(),localDataSource());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;
    }

    /**
     * 配置@Transactional注解事务
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}
使用

在 DynamicDataSourceAspect.java 中配置的service下使用注解的方式指定执行的方法使用哪个数据库。示例参考下方代码:

使用示例

primary数据库数据
primary数据库数据
local 数据库数据
local 数据库数据

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 配置 pom.xml 文件
  • 配置application.yml文件
  • 项目目录结构
  • DataSource.java
  • DynamicDataSourceAspect.java
  • ContextConst.java
  • DataSourceContextHolder .java
  • DynamicDataSource.java
  • MutiplyDataSource.java
  • 使用
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档