SpringBoot+Mybatis-plus+shardingsphere实现分库分表
文章目录
- SpringBoot+Mybatis-plus+shardingsphere实现分库分表
- 介绍
- 引入依赖
- yaml配置
- DDL准备
- 数据库ds0
- 数据库ds1
- entity
- cotroller
- service
- Mapper
- 启动类
- 测试
- 添加
- 修改
- 查询
- 删除
- 总结
介绍
实现亿级数据量分库分表的项目是一个挑战性很高的任务,下面是一个基于Spring Boot的简单实现方案:
-
数据库选择:使用MySQL数据库,因为MySQL在分库分表方面有较成熟的解决方案。
-
分库分表策略:可以采用水平分库分表的策略,根据一定的规则将数据分散存储在不同的数据库和表中,例如可以根据用户ID、订单ID等进行分片。
-
数据分片策略:可以采用基于雪花算法的分布式ID生成器来生成全局唯一的ID,确保数据在不同数据库和表中的唯一性。
-
数据同步:考虑到数据分散存储在不同的数据库和表中,需要实现数据同步机制来保证数据的一致性,可以使用Canal等开源工具来实现MySQL数据的实时同步。
-
连接池优化:在处理大量数据时,连接池的配置尤为重要,可以使用Druid等高性能的连接池来提升数据库连接的效率。
-
缓存机制:考虑使用Redis等缓存工具来缓存热点数据,减轻数据库的压力,提升系统性能。
-
分布式事务:在分库分表的场景下,涉及到跨库事务,可以考虑使用分布式事务框架,如Seata等来保证事务的一致性。
-
监控与调优:实时监控数据库的性能指标,及时调整分片策略和数据库配置,保证系统的稳定性和性能。
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!--分库分表-->
<!-- Sharding-JDBC -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yaml配置
server:
port: 10086
spring:
shardingsphere:
# 数据源配置
datasource:
# 数据源名称,多数据源以逗号分隔
names: db0,db1
db0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/ds0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root
db1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/ds1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root
# 分片规则配置
rules:
sharding:
# 分片算法配置
sharding-algorithms:
database-inline:
# 分片算法类型
type: INLINE
props:
# 分片算法的行表达式(算法自行定义,此处为方便演示效果)
algorithm-expression: db$->{age % 2}
table-inline:
# 分片算法类型
type: INLINE
props:
# 分片算法的行表达式
algorithm-expression: user_$->{age % 3}
tables:
# 逻辑表名称
user:
# 行表达式标识符可以使用 ${...} 或 $->{...},但前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 $->{...}
actual-data-nodes: db${0..1}.user_${0..2}
# 分库策略
database-strategy:
standard:
# 分片列名称
sharding-column: age
# 分片算法名称
sharding-algorithm-name: database-inline
# 分表策略
table-strategy:
standard:
# 分片列名称
sharding-column: age
# 分片算法名称
sharding-algorithm-name: table-inline
# 属性配置
props:
# 展示修改以后的sql语句
sql-show: true
DDL准备
数据库ds0
-- ds0.user_0 definition
CREATE TABLE `user_0` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
-- ds0.user_1 definition
CREATE TABLE `user_1` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
-- ds0.user_2 definition
CREATE TABLE `user_2` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
数据库ds1
-- ds1.user_0 definition
CREATE TABLE `user_0` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
-- ds1.user_1 definition
CREATE TABLE `user_1` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
-- ds1.user_2 definition
CREATE TABLE `user_2` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
entity
package com.kang.sharding.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user")
public class User {
@TableId(value = "id",type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
// getter, setter, toString...
}
cotroller
package com.kang.sharding.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.kang.sharding.entity.User;
import com.kang.sharding.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping ("add")
public boolean createUser(@RequestBody User user) {
return userService.save(user);
}
@PostMapping ("update")
public boolean updateByAge(@RequestBody User user){
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
// 分片数据不允许更新,否则会报错
updateWrapper.eq(User::getAge,user.getAge()).set(User::getName,user.getName());
return userService.update(updateWrapper);
}
@GetMapping ("delete")
public boolean deleteUserByAge(@RequestParam("age") Integer age) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getAge,age);
return userService.remove(queryWrapper);
}
@GetMapping("/{age}")
public List<User> getUserByAge(@PathVariable Integer age) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getAge,age);
return userService.list(queryWrapper);
}
// 其他方法...
}
service
package com.kang.sharding.service;
import com.kang.sharding.entity.User;
import com.kang.sharding.mapper.UserMapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
}
Mapper
package com.kang.sharding.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kang.sharding.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
启动类
package com.kang.sharding;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ShardingJdbcProjectApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingJdbcProjectApplication.class, args);
}
}
测试
添加
修改
查询
删除
总结
这只是个简单的入门示例,后续深入研究