这篇是Springboot操作多数据源,我采用一贯的优雅方式实现:注解 ,切点的方式实现。
进入主题,
先看看这次案例项目的最终目录结构:
然后我这次准备的两个不同的数据库(多个也可以),
一个是game_message , 一个是 game_message_cluster 。
首先先看看我们这次用到的jar,pom.xml(相关jar的作用都有相关的注释):
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mysql连接--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--Druid连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.9</version> </dependency> <!--整合mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <!--AOP--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
然后接下来是application.yml文件:
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver druid: #第一个数据源连接信息 one: url: jdbc:mysql://localhost:3306/game_message?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 username: root password: root #第二个数据源连接信息 two: url: jdbc:mysql://localhost:3306/game_message_cluster?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 username: root password: root #数据库连接池信息 initial-size: 10 max-active: 100 min-idle: 10 max-wait: 60000 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false stat-view-servlet: enabled: true url-pattern: /druid/* filter: stat: log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true #配置下项目端口 server: port: 8023 #mybatis扫描文件路径 mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml #将日志文件生成到系统盘路径 logging: path: F:\\logtest\\log #简单设置一下日志等级 level: web: debug
接下来我们罗列下数据源的名字,这里简单用ONE 、TWO 表示,DataSourceNames.java:
/** * @Author : JCccc * @CreateTime : 2019/8/28 * @Description : **/ public interface DataSourceNames { String ONE = "ONE"; String TWO = "TWO"; }
接着创一个自定义注解,作为aop切点使用,DataSource.java:
import java.lang.annotation.*; /** * @Author : JCccc * @CreateTime : 2019/8/28 * @Description : **/ @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value() default DataSourceNames.ONE; //默认值为ONE,因为后面我们选择配置这个ONE为默认数据库 }
然后是配置AOP切点,DataSourceAspect.java:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import java.lang.reflect.Method; 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; /** * @Author : JCccc * @CreateTime : 2019/8/28 * @Description : **/ @Aspect @Component public class DataSourceAspect implements Ordered { protected Logger logger = LoggerFactory.getLogger(getClass()); /** * 切点: 所有配置 DataSource 注解的方法 */ @Pointcut("@annotation(com.example.demo.config.DataSource)") public void dataSourcePointCut() {} @Around("dataSourcePointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); DataSource ds = method.getAnnotation(DataSource.class); // 通过判断 DataSource 中的值来判断当前方法应用哪个数据源 DynamicDataSource.setDataSource(ds.value()); logger.info("AOP切换数据源成功,数据源为: " + ds.value()); logger.info("set datasource is " + ds.value()); try { return point.proceed(); } finally { DynamicDataSource.clearDataSource(); logger.info("clean datasource"); } } @Override public int getOrder() { return 1; } }
到这里切点AOP的相关配置已经完毕了,接下来到核心的动态数据源配置。
先创建手动切换数据源的核心方法类,DynamicDataSource.java:
然后是用于读取配置信息多数据源,并将其载入的类,DynamicDataSourceConfig.java:
然后是mapper层,MessageboardMapper.java:
然后对应的MessageboardMapper.xml:
mybatis-config.xml :
1.
接下来是较为关键的,就是service层,简单创建一个DataSourceTestService.java:
这里需要认真看,
这个注解标记的方法就是告诉当前方法即将切换数据源,所切换的数据源就是通过切点注解传值,方法当被调用时,就会从切点先进入AOP进行数据源切换设置。
最后,写一个简单的接口来进行多数据源操作测试,
我准备的两个数据库里面都有一张叫表messageboard的表,里面的数据不一样:
然后现在用接口调一下,TestController.java:
将项目运行,可以看到控制台打印,数据源已经都加载了:
用postman调下接口:
可以看到控制台输出:
OK,到此。