SpringBoot动态切换数据源

 Spring提供一个DataSource实现类用于动态切换数据源——AbstractRoutingDataSource

pom.xml


    
    
        org.springframework.boot
        spring-boot-starter-jdbc
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.mybatis.spring.boot
        mybatis-spring-boot-starter
        2.3.0
    
    
        org.springframework.boot
        spring-boot-starter-aop
    
    
        com.alibaba
        druid-spring-boot-starter
        1.2.15
    
    
        mysql
        mysql-connector-java
        runtime
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
        org.mybatis.spring.boot
        mybatis-spring-boot-starter-test
        3.0.2
        test
    



    
        
            org.springframework.boot
            spring-boot-maven-plugin
            
                
                    
                        org.projectlombok
                        lombok
                    
                
            
        
    

大概的项目结构

SpringBoot动态切换数据源_第1张图片

SpringBoot动态切换数据源_第2张图片

@RestController
public class TestController {

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ApplicationContext context;
    @RequestMapping("/test01")
    //@Transactional
    public Object test01(){
        Student student=new Student();
        student.setName("db1");
        student.setAge("18");
        student.setGender("男");
        int i = studentMapper.insertStudent(student);
        User user=new User(null,"db2", "123456");
        int j = userMapper.insertUser(user);

        return i+j;
    }


    @RequestMapping("/test02")
    public Object test02(){
        Student student=new Student();
        student.setName("db1");
        student.setAge("18");
        student.setGender("男");
        int i = studentMapper.insertStudent(student);
        return i;
    }


    @RequestMapping("/test03")
    public Object test03(){
        User user=new User(null,"db2", "123456");
        int i = userMapper.insertUser(user);
        return i;
    }
}

package com.example.demo3.datasource;

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.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author hrui
 * @date 2023/11/2 4:36
 */
@Component
@Aspect
@Order(-100)
public class DataSourceAop {



    @Pointcut("execution(* com.example.demo3.mapper.*.*(..)) && @annotation(com.example.demo3.datasource.DataSourceTypeAnno)")
    public void dataSourcePointcut(){}

    @Around("dataSourcePointcut()")
    public Object doAround(ProceedingJoinPoint pjp){

        MethodSignature methodSignature = (MethodSignature)pjp.getSignature();
        Method method = methodSignature.getMethod();
        DataSourceTypeAnno typeAnno = method.getAnnotation(DataSourceTypeAnno.class);
        String value = typeAnno.value();

        switch (value){
            case "db1":DataSourceUtil.setDB("db1");break;
            case "db2":DataSourceUtil.setDB("db2");break;
        }

        Object result = null ;

        try {
            result = pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }finally {
            DataSourceUtil.setDB("db1");
        }
        return result;
    }
}

注意:这两个事务管理器,并不能处理分布式事务

@Configuration
public class DataSourceConfig {

        /**
         * 数据源1
         * spring.datasource.db1:application.properteis中对应属性的前缀
         * @return
         */
        @Bean(name = "db1")
        @ConfigurationProperties(prefix = "spring.datasource.db1")
        public DataSource dataSourceOne() {
            //return DataSourceBuilder.create().build();
            return  DruidDataSourceBuilder.create().build();
        }//如果选druid连接池

        /**
         * 数据源2
         * spring.datasource.db2:application.properteis中对应属性的前缀
         * @return
         */
        @Bean(name = "db2")
        @ConfigurationProperties(prefix = "spring.datasource.db2")
        public DataSource dataSourceTwo() {
            //return DataSourceBuilder.create().build();

            return  DruidDataSourceBuilder.create().build();
        }

        /**
         * 动态数据源: 通过AOP在不同数据源之间动态切换
         * @return
         */
        @Bean(name = "dynamicDataSource")
        @Primary
        public DataSource dynamicDataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2) {
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            // 默认数据源
            dynamicDataSource.setDefaultTargetDataSource(db1);
            // 配置多数据源
            Map dsMap = new HashMap<>();
            dsMap.put("db1", db1);
            dsMap.put("db2", db2);
            //所有数据源

            dynamicDataSource.setTargetDataSources(dsMap);
            return dynamicDataSource;
        }

//        /**
//         * 配置@Transactional注解
//         * @return
//         */
//        @Bean
//        public PlatformTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {  这个有问题
//            return new DataSourceTransactionManager(dynamicDataSource);
//        }

        @Bean
        @Primary
        public PlatformTransactionManager transactionManager1(@Qualifier("db1") DataSource dynamicDataSource) {
            return new DataSourceTransactionManager(dynamicDataSource);
        }
        @Bean
        public PlatformTransactionManager transactionManager2(@Qualifier("db2") DataSource dynamicDataSource) {
            return new DataSourceTransactionManager(dynamicDataSource);
        }
}

//控制注解的生命周期,什么时候起作用
@Retention(RetentionPolicy.RUNTIME)
//注解的作用对象:  类上   方法上 变量上
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
public @interface DataSourceTypeAnno {
    String value() default "db1";
}

public class DataSourceUtil {
    private static final ThreadLocal local = new ThreadLocal();

    /**
     * 设置数据源名
     * @param dbType
     */
    public static void setDB(String dbType) {
        local.set(dbType);
    }

    /**
     * 获取数据源名
     * @return
     */
    public static String getDB() {
        return local.get();
    }




    /**
     * 清除数据源名
     */
    public static void clearDB() {
        local.remove();
    }
}

@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        log.info("动态获取数据源——{}",DataSourceUtil.getDB());
        return DataSourceUtil.getDB();
    }
}

链接:https://pan.baidu.com/s/1ymxeKYkI-cx7b5nTQX0KWQ 
提取码:6bii 
--来自百度网盘超级会员V4的分享                

你可能感兴趣的:(spring,boot,java,spring)