springboot注解配置多數據源


在項目遇到多數據源的問題,主要是針對部分數據需要單獨處理應用場景;

1.本次項目配置基於springboot+mybatis+maven集成的,首先在yml配置相關如下:其中需要注意單數據源是url,多數據源要改成 jdbc-url,否則會報異常(Error querying database.  Cause: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName)

server:
  port: 8081

spring:
  datasource:
    database1:
      jdbc-url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
    database2:
      jdbc-url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver

#mybatis config
mybatis:
  mapper-locations: classpath*:mapper/*/*.xml

  2.配置好了,需要在啟動類先加上@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class})這個類位置:

import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
3.因為需要用到springboot的aop所以需要導包,在pom.xml文件導入
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

 4.多數據源的結構以下:

 

 內容直接給大家展示:

1.DataSourceAspect
package com.example.demo.config.db.dataSource;
 

import lombok.extern.slf4j.Slf4j;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
 
import java.lang.reflect.Method;
 
/**
 * 多數據源配置, 攔截器配置
 * @author lxp
 * @create 2021-12-28 12:15
 **/
@Aspect
@Component
@Slf4j
// 優先級, 1標識最先執行
@Order(1)
public class DataSourceAspect {
    @Pointcut("execution(* com.example.demo.mapper..*.*(..)))")
    public void dataSourcePoint() {}
 
    @Before("dataSourcePoint()")
    public void before(JoinPoint joinPoint) {
        Object target = joinPoint.getTarget();
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        // 執行方法名
        String methodName = methodSignature.getName();
        // 方法參數
        Class[] parameterTypes = methodSignature.getParameterTypes();
        try {
            // 獲取方法, 直接getClass獲取對象可能為代理對象
            Method method = target.getClass().getInterfaces()[0].getMethod(methodName, parameterTypes);
            // 添加默認數據源
            String dataSource = DataSourceType.Master.getName();
            if (null != method && method.isAnnotationPresent(MyDataSource.class)) {
                MyDataSource targetDataSource = method.getAnnotation(MyDataSource.class);
                dataSource = targetDataSource.value().getName();
            }
            // 此處添加線程對應的數據源到上下文
            // 在AbstractRoutingDataSource子類中拿到數據源, 加載后進行配置
            JdbcContextHolder.putDataSource(dataSource);
            log.info("generate data source : " + dataSource);
        } catch (Exception e) {
            log.info("error", e);
        }
 
    }
 
    /**
     * 清除數據源, 方法執行完成后, 清除數據源
     */
    @After("dataSourcePoint()")
    public void after(JoinPoint joinPoint) {
        JdbcContextHolder.clear();
    }
 
}

2.DataSourceConfig

package com.example.demo.config.db.dataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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;
import java.util.Map;

/**
 * 數據源配置
 */
@Configuration
public class DataSourceConfig {

    @Bean(name =  "database1")
    @ConfigurationProperties(prefix = "spring.datasource.database1")
    public DataSource dataSource1() {
        //database1數據源
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "database2")
    @ConfigurationProperties(prefix = "spring.datasource.database2")
    public DataSource dataSource2() {
        //database2數據源
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name="dynamicDataSource")
    @Primary    //優先使用,多數據源
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 設置默認數據源為first數據源
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        // 配置多數據源,
        // 添加數據源標識和DataSource引用到目標源映射
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put(DataSourceType.Master.getName(), dataSource1());
        dataSourceMap.put(DataSourceType.Slave.getName(), dataSource2());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;

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

}

3.DataSourceType

package com.example.demo.config.db.dataSource;

public enum DataSourceType {

    Master("database1"),
    Slave("database2");
    private String name;
    private DataSourceType(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

4.DynamicDataSource

package com.example.demo.config.db.dataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;


public class DynamicDataSource extends AbstractRoutingDataSource {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @Override
    protected Object determineCurrentLookupKey() {
        logger.info("數據源為{}",JdbcContextHolder.getDataSource());
        return JdbcContextHolder.getDataSource();
    }
    
}
View Code

5.JdbcContextHolder

package com.example.demo.config.db.dataSource;
/**
 * 動態數據源的上下文 threadlocal
 */
public class JdbcContextHolder {
    
    private final static ThreadLocal<String> local = new ThreadLocal<>();
    
    public static void putDataSource(String name) {
        local.set(name);
    }
    
    public static String getDataSource() {
        return local.get();
    }
    /**
     * 清除數據源
     */
    public static void clear() {
        local.remove();
    }

}
View Code

6.MyDataSource

package com.example.demo.config.db.dataSource;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 數據源選擇--自定義注解
 */
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD) 
public @interface MyDataSource {

    DataSourceType value();    //默認主表
    
}
View Code

最后應用就比較簡單了,默認情況有默認的數據庫源,需要調用別的就加注解即可

 

 

 

最后通過調用接口可以看到數據是不同數據庫的數據,完整的過程基本都有,多數據源要把dao層和xml文件隔離開更好的區分!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM