一、先看下简单的库、表结构
ORM框架自动生成的代码,太简单就不上代码了,主要是理解思路
二、引入依赖
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency>
server.port=8085 # 数据源 ds1,ds2,ds3,ds4 spring.shardingsphere.datasource.names=ds1,ds2,ds3,ds4 # 避免实体类绑定多个数据源报错 spring.main.allow-bean-definition-overriding=true # 第一个数据库 spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://8.142.19.202:3306/st-test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.shardingsphere.datasource.ds1.username=root spring.shardingsphere.datasource.ds1.password=你的密码 # 第二个数据库 spring.shardingsphere.datasource.ds2.type=com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.ds2.jdbc-url=jdbc:mysql://8.142.19.202:3306/st-test2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.shardingsphere.datasource.ds2.username=root spring.shardingsphere.datasource.ds2.password=你的密码 # 第三个数据库 spring.shardingsphere.datasource.ds3.type=com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds3.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.ds3.jdbc-url=jdbc:mysql://8.142.19.202:3306/st-test3?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.shardingsphere.datasource.ds3.username=root spring.shardingsphere.datasource.ds3.password=你的密码 # 第四个数据库 spring.shardingsphere.datasource.ds4.type=com.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds4.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.ds4.jdbc-url=jdbc:mysql://8.142.19.202:3306/st-test4?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.shardingsphere.datasource.ds4.username=root spring.shardingsphere.datasource.ds4.password=你的密码 #配置分库规则 spring.shardingsphere.sharding.tables.tb_user.database-strategy.inline.sharding-column=id spring.shardingsphere.sharding.tables.tb_user.database-strategy.inline.algorithm-expression=ds$->{id % 4 + 1} # 指定st_user表的数据分布情况,配置数据节点,行表达式标识符使用 ${...} 或 $->{...}, # 但前者与 Spring 本身的文件占位符冲突,所以在 Spring 环境中建议使用 $->{...} spring.shardingsphere.sharding.tables.tb_user.actual-data-nodes=ds$->{1..4}.tb_user$->{1..4} # 指定st_user表的分片策略,分片策略包括【分片键和分片算法】` spring.shardingsphere.sharding.tables.tb_user.table-strategy.inline.sharding-column=id spring.shardingsphere.sharding.tables.tb_user.table-strategy.inline.algorithm-expression=tb_user$->{id % 4 + 1}
引出两个问题
一)最新版本4.1.1
与你的Spring
版本兼容性有问题,使用下面这个版本即可
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.0-RC1</version> </dependency>
二)dataSource这个bean无法注册
spring.main.allow-bean-definition-overriding=true
三、简单配置结束,上代码测试
package com.example.test05.demo.controller; import com.example.test05.demo.mapper.TbUserMapper; import com.example.test05.demo.model.TbUserDO; import com.example.test05.demo.service.TbUserService; import com.example.test05.demo.tool.JsonData; import jdk.nashorn.internal.objects.annotations.Getter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> * 前端控制器 * </p> * * @author DBC * @since 2021-11-05 */ @RestController @RequestMapping("/tbUserDO") public class TbUserController { @Autowired private TbUserService tbUserService; @Autowired private TbUserMapper tbUserMapper; @PostMapping() public JsonData install() { for (int i = 0; i < 10; i++) { TbUserDO tbUserDO = new TbUserDO(); tbUserDO.setId((long) i); tbUserDO.setName("大猪头" + i); tbUserDO.setAge("" + i); tbUserMapper.insert(tbUserDO); } return JsonData.buildSuccess(); } @GetMapping() public JsonData chaxun() { List<TbUserDO> tbUserDOList = tbUserService.list(); System.out.println(tbUserDOList.size()); return JsonData.buildSuccess(tbUserDOList); } @DeleteMapping() public JsonData shanchu() { tbUserService.removeById(1); return JsonData.buildSuccess(); } @PutMapping() public JsonData xiugai() { TbUserDO tbUserDO = new TbUserDO(); tbUserDO.setId((long) 2); tbUserDO.setName("大猪头666"); tbUserDO.setAge(""); tbUserMapper.updateById(tbUserDO); return JsonData.buildSuccess(); } }
进阶操作——广播表
建对应的表、简单的ORM操作
在配置文件追加广播表
#配置广播表 spring.shardingsphere.sharding.broadcast-tables=tb_type
测试一下
@PostMapping("installType") public JsonData installType() { TbType tbType = new TbType(); tbType.setType("大猪头"); tbTypeMapper.insert(tbType); return JsonData.buildSuccess(); }
进阶操作——绑定表
- 什么是绑定表
- 指分片规则一致的主表和子表
- 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升
先看数据库
画一张图辅助理解
配置对应的分表策略
#配置分库规则 spring.shardingsphere.sharding.tables.tb_user.database-strategy.inline.sharding-column=id spring.shardingsphere.sharding.tables.tb_user.database-strategy.inline.algorithm-expression=ds$->{id % 4 + 1} spring.shardingsphere.sharding.tables.tb_user_item.database-strategy.inline.sharding-column=id spring.shardingsphere.sharding.tables.tb_user_item.database-strategy.inline.algorithm-expression=ds$->{id % 4 + 1} # 指定st_user表的数据分布情况,配置数据节点,行表达式标识符使用 ${...} 或 $->{...}, # 但前者与 Spring 本身的文件占位符冲突,所以在 Spring 环境中建议使用 $->{...} # 指定st_user表的分片策略,分片策略包括【分片键和分片算法】` spring.shardingsphere.sharding.tables.tb_user.actual-data-nodes=ds$->{1..4}.tb_user$->{1..4} spring.shardingsphere.sharding.tables.tb_user.table-strategy.inline.sharding-column=dev_id spring.shardingsphere.sharding.tables.tb_user.table-strategy.inline.algorithm-expression=tb_user$->{dev_id % 4 + 1} # 指定st_user_item表的分片策略,分片策略包括【分片键和分片算法】` spring.shardingsphere.sharding.tables.tb_user_item.actual-data-nodes=ds$->{1..4}.tb_user_item$->{1..4} spring.shardingsphere.sharding.tables.tb_user_item.table-strategy.inline.sharding-column=dev_id spring.shardingsphere.sharding.tables.tb_user_item.table-strategy.inline.algorithm-expression=tb_user_item$->{dev_id % 4 + 1} #配置广播表 spring.shardingsphere.sharding.broadcast-tables=tb_type #配置绑定表 spring.shardingsphere.sharding.binding-tables[0] = tb_user,tb_user_item
我们来看看效果
进阶操作——多种分片策略实战
为了能够有更加自定义的分库分表操作,我们需要在java配置一些我们需要的分库分表策略
#精准分片-水平分表 # 指定product_order表的数据分布情况,配置数据节点,在 Spring 环境中建议使用 $->{...} spring.shardingsphere.sharding.tables.tb_user.actual-data-nodes=ds$->{1..4}.tb_user$->{1..4} #指定精准分片算法(水平分库) 根据id分库 spring.shardingsphere.sharding.tables.tb_user.database-strategy.standard.sharding-column=id spring.shardingsphere.sharding.tables.tb_user.database-strategy.standard.precise-algorithm-class-name=com.example.test05.demo.config.CustomDBPreciseShardingAlgorithm #指定精准分片算法(水平分表) spring.shardingsphere.sharding.tables.tb_user.table-strategy.standard.sharding-column=dev_id spring.shardingsphere.sharding.tables.tb_user.table-strategy.standard.precise-algorithm-class-name=com.example.test05.demo.config.CustomTablePreciseShardingAlgorithm #范围分片(水平分表) spring.shardingsphere.sharding.tables.tb_user.table-strategy.standard.range-algorithm-class-name=com.example.test05.demo.config.CustomRangeShardingAlgorithm
分库配置
CustomDBPreciseShardingAlgorithm
package com.example.test05.demo.config; /** * @author DBC * @date 2022/7/13 14:52 * @network dbc655.top */ import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm; import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue; import java.util.Collection; public class CustomDBPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> { /** * @param dataSourceNames 数据源集合 * 在分库时值为所有分片库的集合 databaseNames * 分表时为对应分片库中所有分片表的集合 tablesNames * @param preciseShardingValue 分片属性,包括 * logicTableName 为逻辑表, * columnName 分片健(字段), * value 为从 SQL 中解析出的分片健的值 * @return */ @Override public String doSharding(Collection<String> dataSourceNames, PreciseShardingValue<Long> preciseShardingValue) { for (String datasourceName : dataSourceNames) { String value = (preciseShardingValue.getValue() % dataSourceNames.size() + 1) + ""; //ds0、ds1 if (datasourceName.endsWith(value)) { return datasourceName; } } return null; } }
CustomTablePreciseShardingAlgorithm
package com.example.test05.demo.config;
/**
* @author DBC
* @date 2022/7/13 14:51
* @network dbc655.top
*/
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import java.util.Collection;
public class CustomTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm
/**
* @param dataSourceNames 数据源集合
* 在分库时值为所有分片库的集合 databaseNames
* 分表时为对应分片库中所有分片表的集合 tablesNames
* @param preciseShardingValue 分片属性,包括
* logicTableName 为逻辑表,
* columnName 分片健(字段),
* value 为从 SQL 中解析出的分片健的值
* @return
*/
@Override
public String doSharding(Collection
for (String datasourceName : dataSourceNames) {
String value = (preciseShardingValue.getValue() % dataSourceNames.size() + 1) + "";
//product_order_0
if (datasourceName.endsWith(value)) {
return datasourceName;
}
}
return null;
}
}
between
有些版本会报错,就算不报错,也会发生恐怖的笛卡尔积!我们需要配置一下CustomRangeShardingAlgorithm
package com.example.test05.demo.config; import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm; import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; /** * @author DBC * @date 2022/7/13 14:34 * @network dbc655.top */ public class CustomRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> { /** * @param dataSourceNames 数据源集合 * 在分库时值为所有分片库的集合 databaseNames * 分表时为对应分片库中所有分片表的集合 tablesNames * @param shardingValue 分片属性,包括 * logicTableName 为逻辑表, * columnName 分片健(字段), * value 为从 SQL 中解析出的分片健的值 * @return */ @Override public Collection<String> doSharding(Collection<String> dataSourceNames, RangeShardingValue<Long> shardingValue) { Set<String> result = new LinkedHashSet<>(); //between 开始值 Long lower = shardingValue.getValueRange().lowerEndpoint(); //between 结束值 Long upper = shardingValue.getValueRange().upperEndpoint(); for (long i = lower; i <= upper; i++) { for (String datasource : dataSourceNames) { String value = (i % dataSourceNames.size() + 1) + ""; if (datasource.endsWith(value)) { result.add(datasource); } } } return result; } }
大功告成!撒花[aru_50]
本文作者为DBC,转载请注明。