1. 前言
连接多数据源的场景非常多哈,比如读写分离,多业务库报表。
2. 环境准备
- JDK1.8
- Mysql 8.0 (主库)
- SQL Server 2008 R2(老业务系统)
- JetBrains IDEA
- Springboot 2.0.4 (Maven项目)
- MyBatis-Plus 3.5.0
3. 配置步骤
1)pom.xml
由于我使用到了MybatisPlus,所以直接使用MybatisPlus官方推荐的dynamic-datasource-spring-boot-starter
。
其次,用到了SqlServer数据库,所以要增加连接SQLServer的JDBC驱动。(SQL Server 2008 R2对应可以使用8.2.2.jre8版本,我是这么搭配的,供参考)
pom.xml
文件中增加:
<dependencies>
<!--mybatis-plus 多数据源配置-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<!-- SQL Server驱动-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.2.2.jre8</version>
</dependency>
</dependencies>
2)修改application.yml文件
这里是重中之重,这里要配置好。但是也没有那么难。
1. 之前的配置:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
datasource:
url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
2. 修改后(多数据源)的配置:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
slave_1:
url: jdbc:sqlserver://localhost:1433;DatabaseName=数据库名
username: sa
password: sa
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
其他更详细的配置可以参考这个官方文档描述。
可以看到,我把之前的mysql数据库做成了master库,也就是主库,也就是上面primary参数中配置的默认库,如果代码中没有明确指定数据库,默认就是master库。
另外添加了一个slave_1库,slave_1是一个sqlserver库。从名字可以看出来,slave可以有N个库。
4. 多数据源的使用
配置好之后当然就是使用了。
当然,使用起来也非常简单,总的来说就是:
在service层(或使用到的方法上)添加注解@DS(“xxxxxxx”)
先简单看一下我的项目结构(只展示关键结构,其他涉密不展示):
- 项目名称
--src
---main
----java
-----com.doph.codepro
------controller
DophController.java
------entity
Doph.java
------mapper
DophMapper.java
------service
DophService.java
-------impl
DophServiceImpl.java
1)entity层
就是简单的实体类,简单写几个字段。@Data注解是lombok的,不知道的可以搜索一下噢~
@Data
@TableName("xxx_doph")
public class Doph {
private static final long serialVersionUID = 1L;
@TableId
private int id;
private String name;
private int age;
}
2)Mapper层
由于用了mybatisPlus,而且业务都是简单业务,所以这几部分代码量都比较少,不会的可以看一下mybatisplus的官网。
public interface DophMapper extends BaseMapper<Doph>{}
3)Service层
public interface DophService extends IService<Doph>{}
4)Impl层(重)
由于业务都是写在Impl层的,所以根据最小化原则,这里使用@DS
注解。
因为我这个文件中的业务操作都是在slave_1
库中的,所以这里的@DS
注解我直接加在了类上。当然,根据自己的业务,加在方法上也是ok的。
@Servcie
@DS("slave_1")
public class DophServiceImpl extends ServiceImpl<DophMapper, Doph> implements DophService{}
如果这里的业务是:
从slave_1库中取出slaveList,再从master库中取出masterList,把name相同的条目插入到slave_2库里面去。
那么有可能出现这种情况(以下是伪代码举例):
@Service
public DophServiceImpl extends ServiceImpl<DophMapper, Doph> implements DophService{
@Autowired
private DophMapper dophMapper;
@Override
@DS("slave_1")
private List<Doph> getSlave(){
List<Doph> slaveList = new ...;
...
return slaveList ;
}
@Override
@DS("master")
private List<Doph> getMaster(){
List<Doph> masterList= new ...;
...
return masterList;
}
@Override
@DS("slave_2")
public void getDiff(){
List<Doph> slaveList = getSlave();
List<Doph> masterList= getMaster();
//循环比较差异
for(...){
if(slave.name.equals(master.name)){
dophMapper.insert(..);
}
}
}
}
5)Controller层
@Controller
@RequestMapping("/doph/")
public class DophController {
@Autowired
private DophService dophService;
@RequestMapping("id1328")
@ResponseBody
public Doph testGetOneDoph(){
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("id",1328);
return dophService.getOne(queryWrapper);
}
}
以上就能完整地输出一个id为1328的Doph Json啦~
5. 结果展示
证明我不是在吹牛逼,当然,里面的数据是一点都不能透露。
后记
之前一直比较害怕多数据源这块。也说不上来原因。当业务达到一定体量之后,或者源于设计之初的规划,多多少少都会碰到多数据源的情况。之前数据库多用Oracle,并且自己也有OCP证书,所以Oracle的DBLink总是解决多数据源的第一选择。今天终于突破了这个小点。其实真的一点都不难,难的是突破自己的心魔。
共勉。