springboot+mybatis配置多数据源并利用aop实现自动切换

硅谷探秘者 1661 0 0

springboot+mybatis配置多数据源并利用aop实现自动切换

1.项目大致结构

2.pom依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </dependency>
      <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>2.0.1</version>
      </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
       
       <!--aop依赖 项目中使用了aop,实现数据源的自动切换-->
  	   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

3.yml配置文件

server:
  port: 8087
  servlet:
        context-path: / #项目路径
 
spring: 
  datasource: 
    main: 
      username: root
      password: jiajia123
      url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
      driver-class-name: com.mysql.jdbc.Driver
    secondary: 
      username: root
      password: jiajia123
      url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
      driver-class-name: com.mysql.jdbc.Driver
    
mybatis:
  mapper-locations: classpath:com/oauth/server/mapper/*Mapper.xml
  type-aliases-package: com.oauth.server.entity
  configuration:      
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #sql日志打印
        call-setters-on-nulls: true #解决返回类型为Map的时候如果值为null将不会封装此字段

在启动类中修改@SpringBootApplication这个配置为:

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})

意思要去掉springboot默认的数据源配置,使用自己定义的数据源配置。

4.DS注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 
 * @author 硅谷探秘者(jia)
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
    String value() default "main";
}

        这个注解是用在service层方法上的,从配置文件中可以看出,配置了两个数据源,主数据源main和辅数据源secondary,如果service方法想访问main这个数据源,则不需要任何配置它默认会访问main数据源,或在方法上加个@DS("main")注解,如果想访问辅数据源secondary则需要在方法上加上@DS("secondary")注解。

例子:

	//访问主数据源
    public void test() {
		// TODO Auto-generated method stub
		testMapper.test();
	}
    //访问辅数据源
	@DS("secondary")
	public void test2() {
		// TODO Auto-generated method stub
		testMapperDb2.test();
	}

        注意这个注解一定是要在运行是可以访问到的,所以要加上@Retention(RetentionPolicy.RUNTIME)这个元注解。

5.数据源配置

/**
 * @author 硅谷探秘者(jia)
 */
public class DataSourceContextHolder {
    /**
     * 默认数据源
     */
    public static final String DEFAULT_DS = "main";
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    // 设置数据源名
    public static void setDB(String dbType) {
        contextHolder.set(dbType);
    }
    // 获取数据源名
    public static String getDB() {
        return (contextHolder.get());
    }
    // 清除数据源名
    public static void clearDB() {
        contextHolder.remove();
    }
}
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author 硅谷探秘者(jia)
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDB();
    }
}
主要配置
package com.oauth.server.conf;

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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
 * @author 硅谷探秘者(jia)
 */
@Configuration
public class DataSourceConfig {

	/**
	 * 	主数据源配置
	 * @return
	 */
    @Bean(name = "main")
    @ConfigurationProperties(prefix = "spring.datasource.main")
    public DataSource main() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 	辅数据源配置
     * @return
     */
    @Bean(name = "secondary")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondary() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 动态数据源: 通过AOP在不同数据源之间动态切换
     *
     * @return
     */
    @Primary
    @Bean(name = "dynamicDS1")
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 默认数据源
        dynamicDataSource.setDefaultTargetDataSource(main());

        // 配置多数据源
        Map<Object, Object> dsMap = new HashMap<Object, Object>(5);
        dsMap.put("main", main());
        dsMap.put("secondary", secondary());

        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }
    /**
     * 配置@Transactional注解事物
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}
aop配置,拦截带@DS注解的方法
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 硅谷探秘者(jia)
 */
@Aspect
@Component
public class DynamicDataSourceAspect {

    @Before("@annotation(DS)")
    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);
            System.out.println(method.getName());
            System.out.println(method.isAnnotationPresent(DS.class));
            // 判断是否存在@DS注解
            if (method.isAnnotationPresent(DS.class)) {
                DS annotation = method.getAnnotation(DS.class);
                // 取出注解中的数据源名
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(dataSource);
        // 切换数据源
        DataSourceContextHolder.setDB(dataSource);
    }

    @After("@annotation(DS)")
    public void afterSwitchDS(JoinPoint point){
        DataSourceContextHolder.clearDB();
    }
}

这样配置基本完成,使用的时候只需要在方法上添加@DS注解,标明你要访问的数据源即可。

server层例子

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.oauth.server.conf.DS;
import com.oauth.server.mapper.TestMapper;
import com.oauth.server.mapper.TestMapperDb2;
@Service
public class TestService {
	@Autowired
	private TestMapper testMapper;
	@Autowired
	private TestMapperDb2 testMapperDb2;
	public void test() {
		// TODO Auto-generated method stub
		testMapper.test();
	}
	@DS("secondary")
	public void test2() {
		// TODO Auto-generated method stub
		testMapperDb2.test();
	}
}

 


评论区
请写下您的评论...
暂无评论...
猜你喜欢
java项目 1394 springboot+mybatisaop(demo)
框架 3372 spring:datasource:main:#主username:rootpassword:123456jdbc-url:jdbc:mysql://localhost:3306/main?useUni
redis,springboot 1067 一、springboot集成redis一般pomdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot
linux系统 6218 方案一:一般方案二:访问某个域名时代理静态资文件方案一:一般  如果以html、htm、gif、jpg、jpeg、bmp、png、ico、txt、js、css结尾的资,均由nginx处理
spring/springmvc 5802 springmvc启时从库中初始化系统常量设计的目标是,把项目的系统常量,放在库中,在项目初始化时从项目中获取信息,反射技术,把key-value对应的值封装进类。1
keepalived,nginx,linux 1277 转移,是通过VRRP来的。  在Keepalived服务正常工作时,主Master节点会不断地向备节点发送(播的方式)心跳消息,以告诉备Backup节点己还活着,当主Master节点发
weblog 2203 vue使v-model(双向绑定)收集表单!DOCTYPEhtmlhtml head metacharset="UTF-8" title/title scriptsrc="js
java 数据库 2609 java项目-库之间定时进行服务(右上方下载)压缩包内附sql脚本,本项目为springboot+mybatis框架,导入项目即可启测试。目的,两个库定时进行同步,定时
归档
2018-11  12 2018-12  33 2019-01  28 2019-02  28 2019-03  32 2019-04  27 2019-05  33 2019-06  6 2019-07  12 2019-08  12 2019-09  21 2019-10  8 2019-11  15 2019-12  25 2020-01  9 2020-02  5 2020-03  16 2020-04  4 2020-06  1 2020-07  7 2020-08  13 2020-09  9 2020-10  5 2020-12  3 2021-01  1 2021-02  5 2021-03  7 2021-04  4 2021-05  4 2021-06  1 2021-07  7 2021-08  2 2021-09  8 2021-10  9 2021-11  16 2021-12  14 2022-01  7 2022-05  1 2022-08  3 2022-09  2 2022-10  2 2022-12  5 2023-01  3 2023-02  1 2023-03  4 2023-04  2 2023-06  3 2023-07  4 2023-08  1 2023-10  1 2024-02  1 2024-03  1 2024-04  1
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job rabbitmq haproxy srs 音视频 webrtc javascript
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。