Browse Source

spring-boot-demo-multi-datasource-mybatis 完成

pull/1/head
Yangkai.Shen 6 years ago
parent
commit
a4b63c31a4
3 changed files with 382 additions and 0 deletions
  1. +382
    -0
      spring-boot-demo-multi-datasource-mybatis/README.md
  2. BIN
      spring-boot-demo-multi-datasource-mybatis/assets/image-20190121152825859.png
  3. BIN
      spring-boot-demo-multi-datasource-mybatis/assets/image-20190121153211509.png

+ 382
- 0
spring-boot-demo-multi-datasource-mybatis/README.md View File

@@ -0,0 +1,382 @@
# spring-boot-demo-multi-datasource-mybatis

> 此 demo 主要演示了 Spring Boot 如何集成 Mybatis 的多数据源。可以自己基于AOP实现多数据源,这里基于 Mybatis-Plus 提供的一个优雅的开源的解决方案来实现。

## 准备工作

准备两个数据源,分别执行如下建表语句

```mysql
DROP TABLE IF EXISTS `multi_user`;
CREATE TABLE `multi_user`(
`id` bigint(64) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`age` int(30) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
AUTO_INCREMENT = 1
CHARACTER SET = utf8
COLLATE = utf8_general_ci;
```

## 导入依赖

```xml
<?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>

<artifactId>spring-boot-demo-multi-datasource-mybatis</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-demo-multi-datasource-mybatis</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>com.xkcoding</groupId>
<artifactId>spring-boot-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</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</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.0</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.7.1</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>

<build>
<finalName>spring-boot-demo-multi-datasource-mybatis</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
```

## 准备实体类

`User.java`

> 1. @Data / @NoArgsConstructor / @AllArgsConstructor / @Builder 都是 lombok 注解
> 2. @TableName("multi_user") 是 Mybatis-Plus 注解,主要是当实体类名字和表名不满足 **驼峰和下划线互转** 的格式时,用于表示数据库表名
> 3. @TableId(type = IdType.ID_WORKER) 是 Mybatis-Plus 注解,主要是指定主键类型,这里我使用的是 Mybatis-Plus 基于 twitter 提供的 雪花算法

```java
/**
* <p>
* User实体类
* </p>
*
* @package: com.xkcoding.multi.datasource.mybatis.model
* @description: User实体类
* @author: yangkai.shen
* @date: Created in 2019-01-21 14:19
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
@Data
@TableName("multi_user")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
private static final long serialVersionUID = -1923859222295750467L;

/**
* 主键
*/
@TableId(type = IdType.ID_WORKER)
private Long id;

/**
* 姓名
*/
private String name;

/**
* 年龄
*/
private Integer age;
}
```

## 数据访问层

`UserMapper.java`

> 不需要建对应的xml,只需要继承 BaseMapper 就拥有了大部分单表操作的方法了。

```java
/**
* <p>
* 数据访问层
* </p>
*
* @package: com.xkcoding.multi.datasource.mybatis.mapper
* @description: 数据访问层
* @author: yangkai.shen
* @date: Created in 2019-01-21 14:28
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public interface UserMapper extends BaseMapper<User> {
}
```

## 数据服务层

### 接口

`UserService.java`

```java
/**
* <p>
* 数据服务层
* </p>
*
* @package: com.xkcoding.multi.datasource.mybatis.service
* @description: 数据服务层
* @author: yangkai.shen
* @date: Created in 2019-01-21 14:31
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public interface UserService extends IService<User> {

/**
* 添加 User
*
* @param user 用户
*/
void addUser(User user);
}
```

### 实现

`UserServiceImpl.java`

> 1. @DS: 注解在类上或方法上来切换数据源,方法上的@DS优先级大于类上的@DS
> 2. baseMapper: mapper 对象,即`UserMapper`,可获得CRUD功能
> 3. 默认走从库: `@DS(value = "slave")`在类上,默认走从库,除非在方法在添加`@DS(value = "master")`才走主库

```java
/**
* <p>
* 数据服务层 实现
* </p>
*
* @package: com.xkcoding.multi.datasource.mybatis.service.impl
* @description: 数据服务层 实现
* @author: yangkai.shen
* @date: Created in 2019-01-21 14:37
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
@Service
@DS("slave")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

/**
* 类上 {@code @DS("slave")} 代表默认从库,在方法上写 {@code @DS("master")} 代表默认主库
*
* @param user 用户
*/
@DS("master")
@Override
public void addUser(User user) {
baseMapper.insert(user);
}
}
```

## 启动类

`SpringBootDemoMultiDatasourceMybatisApplication.java`

> 启动类上方需要使用@MapperScan扫描 mapper 类所在的包

```java
/**
* <p>
* 启动器
* </p>
*
* @package: com.xkcoding.multi.datasource.mybatis
* @description: 启动器
* @author: yangkai.shen
* @date: Created in 2019-01-21 14:19
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
@SpringBootApplication
@MapperScan(basePackages = "com.xkcoding.multi.datasource.mybatis.mapper")
public class SpringBootDemoMultiDatasourceMybatisApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootDemoMultiDatasourceMybatisApplication.class, args);
}

}
```

## 配置文件

`application.yml`

```yaml
spring:
datasource:
dynamic:
datasource:
master:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo-2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
mp-enabled: true
logging:
level:
com.xkcoding.multi.datasource.mybatis: debug
```

## 测试类

```java
/**
* <p>
* 测试主从数据源
* </p>
*
* @package: com.xkcoding.multi.datasource.mybatis.service.impl
* @description: 测试主从数据源
* @author: yangkai.shen
* @date: Created in 2019-01-21 14:45
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
@Slf4j
public class UserServiceImplTest extends SpringBootDemoMultiDatasourceMybatisApplicationTests {
@Autowired
private UserService userService;

/**
* 主从库添加
*/
@Test
public void addUser() {
User userMaster = User.builder().name("主库添加").age(20).build();
userService.addUser(userMaster);

User userSlave = User.builder().name("从库添加").age(20).build();
userService.save(userSlave);
}

/**
* 从库查询
*/
@Test
public void testListUser() {
List<User> list = userService.list(new QueryWrapper<>());
log.info("【list】= {}", JSONUtil.toJsonStr(list));
}
}
```

### 测试结果

主从数据源加载成功

```java
2019-01-21 14:55:41.096 INFO 7239 --- [ main] com.zaxxer.hikari.HikariDataSource : master - Starting...
2019-01-21 14:55:41.307 INFO 7239 --- [ main] com.zaxxer.hikari.HikariDataSource : master - Start completed.
2019-01-21 14:55:41.308 INFO 7239 --- [ main] com.zaxxer.hikari.HikariDataSource : slave - Starting...
2019-01-21 14:55:41.312 INFO 7239 --- [ main] com.zaxxer.hikari.HikariDataSource : slave - Start completed.
2019-01-21 14:55:41.312 INFO 7239 --- [ main] c.b.d.d.DynamicRoutingDataSource : 初始共加载 2 个数据源
2019-01-21 14:55:41.313 INFO 7239 --- [ main] c.b.d.d.DynamicRoutingDataSource : 动态数据源-加载 slave 成功
2019-01-21 14:55:41.313 INFO 7239 --- [ main] c.b.d.d.DynamicRoutingDataSource : 动态数据源-加载 master 成功
2019-01-21 14:55:41.313 INFO 7239 --- [ main] c.b.d.d.DynamicRoutingDataSource : 当前的默认数据源是单数据源,数据源名为 master
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.0.7.1
```

**主**库 **建议** 只执行 **INSERT** **UPDATE** **DELETE** 操作

![image-20190121153211509](assets/image-20190121153211509.png)

**从**库 **建议** 只执行 **SELECT** 操作

![image-20190121152825859](assets/image-20190121152825859.png)

> 生产环境需要搭建 **主从复制**

## 参考

1. Mybatis-Plus 多数据源文档:https://mybatis.plus/guide/dynamic-datasource.html
2. Mybatis-Plus 多数据源集成官方 demo:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter/tree/master/samples

BIN
spring-boot-demo-multi-datasource-mybatis/assets/image-20190121152825859.png View File

Before After
Width: 2796  |  Height: 594  |  Size: 145 kB

BIN
spring-boot-demo-multi-datasource-mybatis/assets/image-20190121153211509.png View File

Before After
Width: 2800  |  Height: 624  |  Size: 196 kB

Loading…
Cancel
Save