1.背景
?
通常一個(gè)系統(tǒng)只需要連接一個(gè)數(shù)據(jù)庫就可以了。但是在企業(yè)應(yīng)用的開發(fā)中往往會和其他子系統(tǒng)交互,特別是對于一些數(shù)據(jù)實(shí)時(shí)性要求比較高的數(shù)據(jù),我們就需要做實(shí)時(shí)連接查詢,而不是做同步。這個(gè)時(shí)候就需要用到多數(shù)據(jù)源。
?
舉個(gè)簡單的例子某企業(yè)要做訂單網(wǎng)上訂單系統(tǒng)這里面就可以涉及到多個(gè)子系統(tǒng)的連接,比如:產(chǎn)品主數(shù)據(jù)的數(shù)據(jù)源,項(xiàng)目管理系統(tǒng)的數(shù)據(jù)源(項(xiàng)目可以產(chǎn)品訂單)等多個(gè)不同數(shù)據(jù)庫類似的數(shù)據(jù)源,他們可能是ORACLE,SQL SERVER,MYSQL等多種混合數(shù)據(jù)源。
?
2.多數(shù)據(jù)源概述
?
基于以上的背景,就會選擇使用多個(gè)數(shù)據(jù)源,一個(gè)數(shù)據(jù)源用于讀一個(gè)數(shù)據(jù)源用于寫?;蛘卟煌臄?shù)據(jù)源混合使用。他的基本思想其實(shí)就是AOP。我們可以通過AOP的思想實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換,通過這個(gè)AOP思想可適用于多種場景、純粹多庫、讀寫分離、一主多從、混合模式等。
動態(tài)數(shù)據(jù)源能進(jìn)行自動切換的核心就是spring底層的AbstractRoutingDataSource進(jìn)行數(shù)據(jù)源的路由,只要繼承了這個(gè)類均可看作是一個(gè)數(shù)據(jù)源的實(shí)現(xiàn)。主要實(shí)現(xiàn)方法是determineCurrentLookupkey,該方法只需要返回?cái)?shù)據(jù)源實(shí)例名稱。
?
3.mybatisplus多數(shù)據(jù)源
?
我們在項(xiàng)目中用mybatisplus的使用用得比較多,這個(gè)動態(tài)數(shù)據(jù)源切換需要實(shí)現(xiàn)的話,比較麻煩,如果有現(xiàn)成的框架使用則最好不過了。恰好mybatiplus就能實(shí)現(xiàn)。文檔地址如下:
?
```properties
https://baomidou.com/pages/a61e1b/#%E6%96%87%E6%A1%A3-documentation
https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611
```
4.使用
?
4.1介紹
?
dynamic-datasource-spring-boot-starter是一個(gè)基于springboot的快速集成多數(shù)據(jù)源的啟動器。
?
特性:
-支持**數(shù)據(jù)源分組**,適用于多種場景純粹多庫讀寫分離一主多從混合模式。
-支持?jǐn)?shù)據(jù)庫敏感配置信息**加密**ENC。
-支持每個(gè)數(shù)據(jù)庫獨(dú)立初始化表結(jié)構(gòu)schema和數(shù)據(jù)庫database。
-支持無數(shù)據(jù)源啟動,支持懶加載數(shù)據(jù)源(需要的時(shí)候再創(chuàng)建連接)。
-支持**自定義注解**,需繼承DS3.2.0+。
-提供并簡化對Druid,HikariCp,BeeCp,Dbcp2的快速集成。
-提供對Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等組件的集成方案。
-提供**自定義數(shù)據(jù)源來源**方案(如全從數(shù)據(jù)庫加載)。
-提供項(xiàng)目啟動后**動態(tài)增加移除數(shù)據(jù)源**方案。
-提供Mybatis環(huán)境下的**純讀寫分離**方案。
-提供使用**spel動態(tài)參數(shù)**解析數(shù)據(jù)源方案。內(nèi)置spel,session,header,支持自定義。
-支持**多層數(shù)據(jù)源嵌套切換**。(ServiceA>>>ServiceB>>>ServiceC)。
-提供**基于seata的分布式事務(wù)方案。
-提供**本地多數(shù)據(jù)源事務(wù)方案。**
?
4.2 約定
?
1.本框架只做**切換數(shù)據(jù)源**這件核心的事情,并**不限制你的具體操作**,切換了數(shù)據(jù)源可以做任何CRUD。
2.配置文件所有以下劃線`_`分割的數(shù)據(jù)源**首部**即為組的名稱,相同組名稱的數(shù)據(jù)源會放在一個(gè)組下。
3.切換數(shù)據(jù)源可以是組名,也可以是具體數(shù)據(jù)源名稱。組名則切換時(shí)采用負(fù)載均衡算法切換。
4.默認(rèn)的數(shù)據(jù)源名稱為**master**,你可以通過`spring.datasource.dynamic.primary`修改。
5.方法上的注解優(yōu)先于類上注解。
6.DS支持繼承抽象類上的DS,暫不支持繼承接口上的DS。
?
4.3 使用
?
4.3.1準(zhǔn)備數(shù)據(jù)庫
docker run --name mysq -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7
創(chuàng)建2個(gè)數(shù)據(jù)庫
create database test1;
create database test2;
use test2;
-- auto-generated definition
create table tb_user
(
id int auto_increment
primary key,
name varchar(200) null
);
insert into tb_user values(1,"wangwu");
use test1;
-- auto-generated definition
create table tb_user
(
id int auto_increment
primary key,
name varchar(200) null
);
insert into tb_user values(1,"zhangsan");
一個(gè)作為主庫一個(gè)作為從庫。
?
4.3.2 springboot創(chuàng)建工程
?
添加依賴:
<?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.itheima</groupId>
<artifactId>dynamic</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
</dependencies>
</project>
啟動類:
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DynamicApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicApplication.class,args);
}
}
4.3.3配置yml
spring:
datasource:
dynamic:
primary: master #設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,默認(rèn)值即為master
strict: false #嚴(yán)格匹配數(shù)據(jù)源,默認(rèn)false. true未匹配到指定數(shù)據(jù)源時(shí)拋異常,false使用默認(rèn)數(shù)據(jù)源
datasource:
master:
url: jdbc:mysql://192.168.211.253:3306/test1
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver # 3.2.0開始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://192.168.211.253:3306/test2
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
#......省略
#以上會配置一個(gè)默認(rèn)庫master,一個(gè)組slave下有兩個(gè)子庫slave_1
4.3.4使用注解來切換數(shù)據(jù)源
?
使用**DS**切換數(shù)據(jù)源,使用方式如下:
?
**DS**可以注解在方法上或類上,**同時(shí)存在就近原則方法上注解優(yōu)先于類上注解**。
|注解|結(jié)果|
|-------------|----------------------------------------|
|沒有DS|默認(rèn)數(shù)據(jù)源|
|DS
"dsName"
|dsName可以為組名也可以為具體某個(gè)庫的名稱|
?
例如:
@Service
@DS("slave")
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public List selectAll() {
return jdbcTemplate.queryForList("select * from user");
}
@Override
@DS("slave_1")
public List selectByCondition() {
return jdbcTemplate.queryForList("select * from user where age >10");
}
}
4.3.5創(chuàng)建CSD
po:
package com.itheima.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("tb_user")
public class User {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("name")
private String name;
}
controller
package com.itheima.controller;
import com.itheima.po.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User get(@PathVariable(name="id")Integer id){
return userService.getById(id);
}
}
service
```
public interface UserService{
User getById
Integer id
;
}
```
package com.itheima.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.itheima.dao.UserDao;
import com.itheima.po.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@DS("slave_1")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User getById(Integer id) {
return userDao.selectById(id);
}
}
注意:如上:DS注解用于指定使用哪一個(gè)數(shù)據(jù)源。
?
dao
package com.itheima.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.po.User;
public interface UserDao extends BaseMapper<User> {
}
啟動類:
@SpringBootApplication
@MapperScan(basePackages = "com.itheima.dao")
public class DynamicApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicApplication.class,args);
}
}
4.3.6測試
?
+當(dāng)使用DS注解指定master的時(shí)候:
```
Service
DS
"master"
public class UserServiceImpl implements UserService{
Autowired
private UserDao userDao;
Override
public User getById
Integer id
{
return userDao.selectById
id
;
}
}
```
重啟項(xiàng)目,瀏覽器發(fā)送請求:http://localhost:8080/user/1
?
得到結(jié)果:
```
{"id":1,"name":"zhangsan"}
```
+當(dāng)使用DS注解指定slave_1的時(shí)候
```
Service
DS
"slave_1"
public class UserServiceImpl implements UserService{
Autowired
private UserDao userDao;
Override
public User getById
Integer id
{
return userDao.selectById
id
;
}
}
```
重啟項(xiàng)目,瀏覽器發(fā)送請求:http://localhost:8080/user/1
?
得到結(jié)果:
{"id":1,"name":"wangwu"}
測試成功。
?
5.總結(jié)
?
使用mybatisplus的動態(tài)數(shù)據(jù)源切換非常方便,只需添加依賴,并在yaml中配置數(shù)據(jù)源的名稱和地址,并在service的實(shí)現(xiàn)類中使用注解來指定實(shí)現(xiàn)切換即可。下一章節(jié)我們來看看如何使用AOP來實(shí)現(xiàn)不需要修改代碼就能動態(tài)切換數(shù)據(jù)源。
?
+添加依賴
+添加yaml配置文章來源:http://www.zghlxwxcb.cn/news/detail-459185.html
+在業(yè)務(wù)方法上或者業(yè)務(wù)類上添加 DS注解文章來源地址http://www.zghlxwxcb.cn/news/detail-459185.html
到了這里,關(guān)于mybatisplus快速實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!