shardingjdbc分库分表----自定义生成主键
每天多学一点点~
话不多说,这就开始吧…
1.前言
好久没写博客了,主要是新入职的公司太忙,被996摧残了两个多月之后,再也不想去大厂了。。。最近滴滴出事,隔壁的T3出行开始007了好像,资本是真的可怕,手动狗头。。。
吐槽完毕,今天正好闲暇,之前写过一篇 ShardingSphere分库分表----取模和按日期分表,用的是雪花算法作为主键。但有时我们需要清晰可见的主键,比如按照入库时间这样的,所以这次介绍一下在sharding中如何自定义主键策略。
2. proerties配置文件
书接上回,pom依赖和上文都一样。
application-time.properties配置文件
# ===================== db 以 订单id 取模 table 以 订单创建时间 分库 ===================================================
#配置数据源 boke_1 boke_2
spring.shardingsphere.datasource.names=b0,b1
#默认数据源是b0
spring.shardingsphere.sharding.default-data-source-name=b0
# boke_0 数据源配置
spring.shardingsphere.datasource.b0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.b0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.b0.jdbc-url=jdbc:mysql://localhost:3306/boke_0?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull
spring.shardingsphere.datasource.b0.username=root
spring.shardingsphere.datasource.b0.password=root
# boke_1 数据源配置
spring.shardingsphere.datasource.b1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.b1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.b1.jdbc-url=jdbc:mysql://localhost:3306/boke_1?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull
spring.shardingsphere.datasource.b1.username=root
spring.shardingsphere.datasource.b1.password=root
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=b$->{0..1}.t_order_$->{2020..2021}_$->{1..12}
# 自定义 分片算法
# 分库分片健 database-strategy 数据库策略
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.sharding-column=order_id
# 自定义 分片 策略
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=com.boke.order.sharding.time.DBShardingAlgorithm
# table-strategy 表 的 策略
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.sharding-column=create_time
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.precise-algorithm-class-name=com.boke.order.sharding.time.TableShardingAlgorithm
###########使用SNOWFLAKE算法生成主键
#spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
#spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
# 雪花算法的workId 机器为标识 0-1024
#spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
############ 使用自定义主键 spi 机制 ############# com.boke.order.spi.OrderByRedisKeyGenerator
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=CUSTOM
spring.shardingsphere.sharding.tables.t_order.key-generator.props.redis.prefix=order:id:prefix:
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
3. spi自定义主键生成的类
在上面的proerties中,定义了
props.redis.prefix=order🆔prefix:
和
props.worker.id=123
我们通过spi机制,写一个自定义生成的类,代码如下:
-
在META-INF/services 下新建org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator
-
OrderByRedisKeyGenerator类实现
package com.boke.order.spi;
import com.boke.order.BokeOrderApplication;
import com.boke.order.utils.RedisOpsUtil;
import com.boke.order.utils.SpringBeanFactory;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* ,;,,;
* ,;;'( 社
* __ ,;;' ' \ 会
* /' '\'~~'~' \ /'\.) 主
* ,;( ) / |. 义
* ,;' \ /-.,,( ) \ 码
* ) / ) / )| 农
* || || \)
* (_\ (_\
*
* @author :zjq
* @date :Created in 2021/07/11 13:55
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description: 全局唯一主键生成器【分库分表专用】
**/
@Slf4j
public class OrderByRedisKeyGenerator implements ShardingKeyGenerator {
// 写法一
// @Getter
// private final String type = "CUSTOM";
// @Getter
// @Setter
// private Properties properties = new Properties();
// 写法 二
@Override
public String getType() {
return "CUSTOM";
}
// 不需要,sharding 底层帮你做了 否则你想添加其他的东西
// 对应 spring.shardingsphere.sharding.tables.t_order.key-generator.props.redis.prefix
/**
* 不需要,sharding 底层帮你做了 否则你想添加其他的东西
* 对应 spring.shardingsphere.sharding.tables.t_order.key-generator.props.redis.prefix 配置
* 至于为何:
* 源码追溯: org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration
*
*/
private Properties properties = new Properties();
@Override
public Properties getProperties() {
return properties;
}
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
/**
* 生成18位订单编号:8位日期+3位平台ID+7位以上自增id
* 需在分表策略当中配置如下属性
* spring.shardingsphere.sharding.tables.t_order.key-generator.column=id
* spring.shardingsphere.sharding.tables.t_order.key-generator.type=CUSTOM
* spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
* spring.shardingsphere.sharding.tables.t_order.key-generator.props.redis.prefix=order:id:prefix:
*/
@Override
public Comparable<?> generateKey() {
StringBuilder sb = new StringBuilder();
RedisOpsUtil redisOpsUtil = SpringBeanFactory.getBean("redisOpsUtil");
String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
String key = properties.getProperty("redis.prefix") + date;
//增长值
Long increment = null;
if (redisOpsUtil.hasKey(key)) {
increment = redisOpsUtil.incr(key, 1);
} else {
increment = redisOpsUtil.incr(key, 1);
redisOpsUtil.expire(key, 24, TimeUnit.HOURS);
}
sb.append(date);
sb.append(String.format("%03d", Integer.parseInt(properties.getProperty("worker.id"))));
String incrementStr = increment.toString();
if (incrementStr.length() <= 7) {
sb.append(String.format("%07d", increment));
} else {
sb.append(incrementStr);
}
return Long.parseLong(sb.toString());
}
}
其中,Properties 类sharding底层帮你封装了,会帮我们从properties配置文件中获取以
spring.shardingsphere.sharding.tables.t_order.key-generator.props. 开头的内容,即
redis.prefix=order🆔prefix: 和 worker.id=123,然后通过redis的incr院子操作获取自增的数,按照日期进行拼接,获取我们想要的主键id。
如果有其他的业务需求,也可以根据实际情况自己定制。
分库分表用起来虽然简单,但是能不能还是尽量别分,从业务角度考虑如何不拆分。分了之后,数据迁移,分布式事务,某些sql不支持,mybaits的批量插入等等都要考虑进去。
4. 结语
世上无难事,只怕有心人,每天积累一点点,fighting!!!