Springboot+Mybatis AOP注解動態切換數據源


在開發中因需求在項目中需要實現多數據源(雖然項目框架是SpringCloud,但是因其中只是單獨的查詢操作,覺得沒必要開發一個項目,所以采用多數據源來進行實現)

 

1.在配置文件中創建多個數據連接配置

spring.datasource.primary.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.primary.url=jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.driverClassName = com.mysql.jdbc.Driver
spring.datasource.primary.max-wait=10000
spring.datasource.primary.max-idle=8
spring.datasource.primary.min-idle=8
spring.datasource.primary.initial-size=10
spring.datasource.primary.max-active=20
spring.datasource.primary.test-on-borrow=true
spring.datasource.primary.test-while-idle=true
spring.datasource.primary.validation-query=SELECT 1 FROM DUAL
spring.datasource.primary.time-between-eviction-runs-millis=300000
spring.datasource.primary.min-evictable-idle-time-millis=1800000


spring.datasource.second.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.second.url=jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false
spring.datasource.second.username=root
spring.datasource.second.password=root
spring.datasource.second.driverClassName = com.mysql.jdbc.Driver
spring.datasource.second.max-wait=10000
spring.datasource.second.max-idle=8
spring.datasource.second.min-idle=8
spring.datasource.second.initial-size=10
spring.datasource.second.max-active=20
spring.datasource.second.test-on-borrow=true
spring.datasource.second.test-while-idle=true
spring.datasource.second.validation-query=SELECT 1 FROM DUAL
spring.datasource.second.time-between-eviction-runs-millis=300000
spring.datasource.second.min-evictable-idle-time-millis=1800000

 

 2.配置完成后需要創建數據源的連接工廠

 2.1第一個數據源連接配置

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
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.core.io.support.PathMatchingResourcePatternResolver;

@Configuration
//配置mybatis的接口類放的地方
@MapperScan(basePackages = "com.cloud.demo.dao.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class DataSourceFirstConfig {
    // 將這個對象放入Spring容器中
    @Bean(name = "primaryDataSource")
    // 表示這個數據源是默認數據源
 @Primary // 讀取application.properties中的配置參數映射成為一個對象
    // prefix表示參數的前綴
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource getDateSource1() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "primarySqlSessionFactory")
    // 表示這個數據源是默認數據源
 @Primary // @Qualifier表示查找Spring容器中名字為test1DataSource的對象
    public SqlSessionFactory test1SqlSessionFactory(@Qualifier("primaryDataSource") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(
                // 設置mybatis的xml所在位置
                new PathMatchingResourcePatternResolver().getResources("classpath*:com/cloud/demo/mapping/primary/*.xml"));
        return bean.getObject();
    }
    @Bean("primarySqlSessionTemplate")
    // 表示這個數據源是默認數據源
 @Primary public SqlSessionTemplate test1sqlsessiontemplate(
            @Qualifier("primarySqlSessionFactory") SqlSessionFactory sessionfactory) {
        return new SqlSessionTemplate(sessionfactory);
    }
}

  2.2第二個數據源配連接配置

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

@Configuration
@MapperScan(basePackages = "com.cloud.demo.dao.second", sqlSessionFactoryRef = "secondSqlSessionFactory")
public class DataSourceSecondConfig {
    @Bean(name = "secondDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource getDateSource2() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory test2SqlSessionFactory(@Qualifier("secondDataSource") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath*:com/cloud/demo/mapping/second/*.xml"));
        return bean.getObject();
    }
    @Bean("secondSqlSessionTemplate")
    public SqlSessionTemplate test2sqlsessiontemplate(
            @Qualifier("secondSqlSessionFactory") SqlSessionFactory sessionfactory) {
        return new SqlSessionTemplate(sessionfactory);
    }
}

PS: @Primary注解一定要配置,否則不知道哪個是默認數據源配置

 

3.保存切換數據源

public class DataSourceContextHolder {
    
    //默認數據源
    public static final String DEFAULT_DS = "primaryDataSource";
 
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
 
    // 設置數據源名
    public static void setDB(String dbType) {
        System.out.println("切換到{"+dbType+"}數據源");
        contextHolder.set(dbType);
    }
 
    // 獲取數據源名
    public static String getDB() {
        return (contextHolder.get());
    }
 
    // 清除數據源名
    public static void clearDB() {
        contextHolder.remove();
    }
}

4.當前數據源

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        System.out.println("數據源為"+DataSourceContextHolder.getDB());
        return DataSourceContextHolder.getDB();
    }

}

5.創建自定義注解

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 DataSource {
    String value() default "primaryDataSource";
}

6.使用AOP創建切點

import java.lang.reflect.Method;

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;

@Aspect
@Component
public class DynamicDataSourceAspect {
    @Before("@annotation(DataSource)")
    public void beforeSwitchDS(JoinPoint point){
        //獲得當前訪問的class
        Class<?> className = point.getTarget().getClass();
        //獲得訪問的方法名
        String methodName = point.getSignature().getName();
        //得到方法的參數的類型
        Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
        String dataSource = DataSourceContextHolder.DEFAULT_DS;
        try {
            // 得到訪問的方法對象
            Method method = className.getMethod(methodName, argClass);
            // 判斷是否存在@DS注解
            if (method.isAnnotationPresent(DataSource.class)) {
                DataSource annotation = method.getAnnotation(DataSource.class);
                // 取出注解中的數據源名
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 切換數據源
        DataSourceContextHolder.setDB(dataSource);
    }
    
    @After("@annotation(DataSource)")
    public void afterSwitchDS(JoinPoint point){
        DataSourceContextHolder.clearDB();
    }
}

7.啟動類修改:


@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @MapperScan(basePackages
= {"com.cloud.demo.*.dao"})public class TrusteeInterfaceApplication { public static void main(String[] args) { SpringApplication.run(TrusteeInterfaceApplication.class, args); } }

 

8.使用方式

只需要在service的實現類中的方法上方使用注解即可

@Override
@DataSource("primaryDataSource")
public void saveTGLsbrkjg(TgLsbrkjg tgLsbrkjg) {
    tableMapper.saveTg(tgLsbrkjg);
}

 


免責聲明!

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



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