mysql分库分表 sharding-jdbc 3.0的代码实现
一、依赖包
SpringBoot 用的是 2.0.6.RELEASE 版本。
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>3.0.0.M4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.6</version>
</dependency>
注意,sharding-jdbc 不同版本的差异较大,如果引入 其他版本的 sharding-jdbc,以下的配置有可能不兼容。
二、mysql 建表
CREATE TABLE tb_shard_test
(
id INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增id',
order_id VARCHAR(25) NOT NULL UNIQUE COMMENT '订单号,唯一',
pay_status INT UNSIGNED DEFAULT 0 COMMENT '10:未支付,20:支付成功,30:支付失败, 40:已下单,50:申请退款,60:退款成功,70:退款失败 ',
user_id BIGINT(20) NOT NULL COMMENT '用户id',
total_price DECIMAL(25, 2) DEFAULT 0.00 COMMENT '交易金额',
result TEXT COMMENT '结果',
order_desc VARCHAR(128) DEFAULT '' COMMENT '订单描述',
order_date DATE DEFAULT NULL COMMENT '订单日期',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间,默认当前时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间,更新时默认当前时间',
is_delete TINYINT(1) DEFAULT 0 COMMENT '是否删除,0表示否,1表示是',
PRIMARY KEY (id),
INDEX idx_order (order_id)
) ENGINE = INNODB
DEFAULT CHARSET = utf8
AUTO_INCREMENT = 1 COMMENT ='示例表';
建立多个分表:
CREATE TABLE tb_shard_test_0 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_1 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_2 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_3 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_4 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_5 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_6 LIKE tb_shard_test;
CREATE TABLE tb_shard_test_7 LIKE tb_shard_test;
配置环境:
在 application.properties 中指定使用 哪个环境的配置文件:
server.port=8080
spring.profiles.active=dev
当 spring.profiles.active 为 dev 时,会读取 application-dev.properties 的配置。
当 spring.profiles.active 为 test 时,会读取 application-test.properties 的配置。
三、sharding 配置
新建 application-dev.properties 文件,配置值如下:
# 数据源命名。这个名称,后面会经常用到。
sharding.jdbc.datasource.names=ds
# default-data-source-name 默认的数据源,可以是 sharding.jdbc.datasource.names 配置的值
sharding.jdbc.config.sharding.default-data-source-name=ds
# tables后面是 表名 tb_shard_test,自行修改。 ds是前面配置的数据源名称。0..7 表示分为 8 张表。
sharding.jdbc.config.sharding.tables.tb_shard_test.actual-data-nodes=ds.tb_shard_test_$->{0..7}
# 分表的字段
sharding.jdbc.config.sharding.tables.tb_shard_test.table-strategy.standard.sharding-column=order_id
# 指定分表策略的类的路径。路径自行修改
sharding.jdbc.config.sharding.tables.tb_shard_test.table-strategy.standard.precise-algorithm-class-name=com.example.demo.config.MyShardingAlgorithm
sharding.jdbc.config.sharding.props.sql.show=true
# 数据库连接池,如果是 Druid,则使用 com.alibaba.druid.pool.DruidDataSource
# 注意 sharding.jdbc.datasource. 后面的值,必须是 sharding.jdbc.datasource.names 配置的值。比如配置为 ds,那在使用时就用 ds。
sharding.jdbc.datasource.ds.type=com.zaxxer.hikari.HikariDataSource
# 如果是高版本的mysql,driver-class-name 换成 com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.ds.url=jdbc:mysql://mysql的ip:端口/库名?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
sharding.jdbc.datasource.ds.jdbcUrl=jdbc:mysql://mysql的ip:端口/库名?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
sharding.jdbc.datasource.ds.username=账号
sharding.jdbc.datasource.ds.password=密码
# 以下是可选的配置,可以不加上
#sharding.jdbc.datasource.ds.initialSize=0
#sharding.jdbc.datasource.ds.maxActive=20
#sharding.jdbc.datasource.ds.maxIdle=10
#sharding.jdbc.datasource.ds.minIdle=5
#sharding.jdbc.datasource.ds.maxWait=60000
#sharding.jdbc.datasource.ds.timeBetweenEvictionRunsMillis=60000
#sharding.jdbc.datasource.ds.minEvictableIdleTimeMillis=300000
#sharding.jdbc.datasource.ds.validationQuery=SELECT 'x'
#sharding.jdbc.datasource.ds.testWhileIdle=true
#sharding.jdbc.datasource.ds.testOnBorrow=false
#sharding.jdbc.datasource.ds.testOnReturn=false
##spring.datasource.connection-init-sqls=set names utf8mb4;
#sharding.jdbc.datasource.ds.filters=stat
自定义分表策略:
注意,这个类要放在对应的路径。
比如 properties 文件中配置的是:
sharding.jdbc.config.sharding.tables.表名.table-strategy.standard.precise-algorithm-class-name=com.example.demo.config.MyShardingAlgorithm
那么类就要放在 com.example.demo.config.MyShardingAlgorithm 这个路径。
import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import java.util.Collection;
/**
* 自定义分表策略。根据 分表字段的hashCode 取对8进行取余。
* 根据分表策略,返回表名。
*/
public class MyShardingAlgorithm implements PreciseShardingAlgorithm<String> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
String shardingStr = shardingValue.getValue().trim();
for (String tableName : availableTargetNames) {
if (tableName.endsWith(Math.abs(shardingStr.hashCode()) % 8 + "")) {
return tableName;
}
}
throw new IllegalArgumentException();
}
}
Service层代码
此处用的是 Mybatis-Plus,相关讲解见:https://www.cnblogs.com/expiator/p/17125880.html
也可以直接用 mybatis 写sql。
增删改查时,不需要特别指定是哪一张分表。sharding-jdbc 会进行处理。
@Service
public class ShardTestServiceImpl extends ServiceImpl<ShardTestMapper, ShardTestEntity> implements ShardTestService {
/**
* 根据 orderId 查询结果
*/
public List<ShardTestEntity> getByOrderId(String orderId) {
LambdaQueryWrapper<ShardTestEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShardTestEntity::getOrderId, orderId);
return list(queryWrapper);
}
}
测试代码:
由于是根据 orderId的 hashCode 对8取余进行分表。
orderId为 12345 时, 计算结果为 3,保存/查询就都在 tb_shard_test_3 表。
保存数据后,可以在 tb_shard_test_3 查到。
orderId为 1234 时, 计算结果为 2,保存/查询就都 tb_shard_test_2 表。
如下:
@Test
public void testSave() throws Exception {
String orderId = "12345";
long userId = 123L;
//根据 hashCode 对8取余,可以知道数据存在哪一张分表上。
int partition = Math.abs(orderId.hashCode()) % 8;
System.out.println("partition:"+ partition);
ShardTestEntity shardTestEntity = new ShardTestEntity();
shardTestEntity.setOrderId(orderId);
shardTestEntity.setUserId(userId);
//保存
shardTestService.save(shardTestEntity);
}
@Test
public void testGetByOrderId() throws Exception {
String orderId = "1234";
//根据 hashCode 对8取余,可以知道数据存在哪一张分表上。
int partition = Math.abs(orderId.hashCode()) % 8;
System.out.println("partition:"+ partition);
List<ShardTestEntity> entities = shardTestService.getByOrderId(orderId);
System.out.println(JSON.toJSONString(entities));
}
报错:
- sharding-jdbc 报错:
io.shardingsphere.core.exception.ShardingException: Cannot find data source in sharding rule, invalid actual data node is
解决方法:
使用的数据源,必须 是 sharding.jdbc.datasource.names 配置的值。
比如 配置了:
sharding.jdbc.datasource.names=ds
那么 sharding.jdbc.config.sharding.tables.表名.actual-data-nodes 的配置,就只能是 ds.加表名,示例:
sharding.jdbc.config.sharding.tables.tb_shard_test.actual-data-nodes=ds.tb_shard_test_$->{0..7}
- sharding-jdbc 报错:
java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
添加配置:
# ds代替为 sharding.jdbc.datasource.names 对应的值。自行修改。
sharding.jdbc.datasource.ds.jdbcUrl=jdbc:mysql://mysql的ip:端口号/库名?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
- sharding-jdbc报错:
qualifying bean of type 'org.apache.shardingsphere.infra.config.mode.ModeConfiguration' available: expected at least 1 bean which qualifies as autowire candidate
添加以下配置:
spring.shardingsphere.mode.type=Memory
如果还是不行,有可能是没有指定配置文件的位置,可以把配置放到默认的 application.properties 文件中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2016-06-29 android笔记:ListView及ArrayAdapter