今天在一个项目中遇到需要连接两个数据库去进行读取数据的操作,网上查了很多文章,踩坑很多,希望用我的实践带给你帮助
项目结构
需要提前准备的东西
- 两个数据库实例
- 在数据库实例中创建表(可以相同也可以不相同,我目前是相同的)
- springboot环境
pom如下(我全部依赖,根据自己情况加,核心依赖我已经标注)
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xgt588</groupId>
<artifactId>MultipleDataSources</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--多数据源整合核心-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.8.0</version>
</dependency>
<!--多数据源整合核心-->
</dependencies>
</project>
application.yml如下
必须有master库,不可以改,我尝试改过,会无法加载导致项目无法启动。其他库的名字可以随便起,不过要记住自己起的名字,接下来会使用到。我的两个库的key是master和db2
spring:
datasource:
p6spy: true
dynamic:
datasource:
master:
username: xxx
password: xxx
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://xxx/alice_test?useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
db2:
username: xxx
password: xxx
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://xxx/alice_test_two?useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
下面开始撸代码
首先是实体类
package com.liuliuliuliu.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Module implements Serializable {
private Long id;
private String name;
private String title;
private String type;
private Integer priority;
private String extra;
private Date createTime;
private Date updateTime;
}
其次是mapper 我这里测试使用的比较简单,使用的注解写sql,也可以使用xml的形式,与平常使用方式相同。
package com.liuliuliuliu.mapper;
import com.liuliuliuliu.entity.Module;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface ModuleMapper {
@Select("select * from module where id = #{id}")
Module getById(Long id);
}
接下来是两个service
service1
package com.liuliuliuliu.service;
import com.liuliuliuliu.entity.Module;
public interface ModuleService1 {
Module getById(Long id);
}
serviceImpl1
package com.liuliuliuliu.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.liuliuliuliu.entity.Module;
import com.liuliuliuliu.mapper.ModuleMapper;
import com.liuliuliuliu.service.ModuleService1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author liushisheng
* @Date 2021-03-18
*/
@DS("master")
@Service("moduleService1")
public class ModuleService1Impl implements ModuleService1 {
@Autowired
private ModuleMapper mapper;
@Override
public Module getById(Long id) {
return mapper.getById(id);
}
}
service2
package com.liuliuliuliu.service;
import com.liuliuliuliu.entity.Module;
public interface ModuleService2 {
Module getById(Long id);
}
serviceImpl2
package com.liuliuliuliu.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.liuliuliuliu.entity.Module;
import com.liuliuliuliu.mapper.ModuleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.liuliuliuliu.service.ModuleService2;
/**
* @Author liushisheng
* @Date 2021-03-18
*/
@DS("db2")
@Service("moduleService2")
public class ModuleService2Impl implements ModuleService2 {
@Autowired
private ModuleMapper mapper;
@Override
public Module getById(Long id) {
return mapper.getById(id);
}
}
注意看这里@DS,就是使用这个注解来指定需要切换到的数据源,DS内部填写的值就是yml里面配置的key。
DS注解源码如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baomidou.dynamic.datasource.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {
String value();
}
最后是controller以及测试结果
package com.liuliuliuliu.controller;
import com.liuliuliuliu.entity.Module;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.liuliuliuliu.service.ModuleService1;
import com.liuliuliuliu.service.ModuleService2;
/**
* @Author liushisheng
* @Date 2021-03-18
*/
@RestController
public class ModuleController {
@Autowired
private ModuleService1 moduleService1;
@Autowired
private ModuleService2 moduleService2;
@GetMapping("module1")
public Module getById1(@RequestParam("id") Long id) {
return moduleService1.getById(id);
}
@GetMapping("module2")
public Module getById2(@RequestParam("id") Long id) {
return moduleService2.getById(id);
}
}
测试结果
总结
dynamic-datasource-spring-boot-starter封装好了切换数据源,只需要按照其约定配置好配置文件即可,使用Sping的AOP实现繁琐并且出错率很高。