目录
一、概述
二、自定义主键生成策略
(1)、自定义MyShardingKeyGenerator
(2)、SPI接口配置
(3)、配置主键ID生成策略
(4)、测试数据插入
一、概述
实际应用中,大部分场景按照MySQL主键ID自增就能满足需求,但是在分库分表后,MySQL的自增主键就不能使用了,为了避免重复,我们需要全局唯一的ID,比如会员表的会员ID、订单表的订单ID等。
ShardingSphere不仅提供了内置的分布式主键生成器,例如UUID、SNOWFLAKE,默认使用SNOWFLAKE,其对应实现类如下:
public final class UUIDShardingKeyGenerator implements ShardingKeyGenerator {
// UUID: 采用UUID.randomUUID()的方式产生分布式主键
}
public final class SnowflakeShardingKeyGenerator implements ShardingKeyGenerator {
// SNOWFLAKE: 雪花算法,生成64bit的长整型数据
}
还抽离出分布式主键生成器的接口,方便用户自行实现自定义的自增主键生成器。通过观察sharding-jdbc源码,可以看到这两种主键ID生成策略都是实现了ShardingKeyGenerator接口,可以看到,如果我们需要自定义主键生成策略,只需要实现ShardingKeyGenerator接口,然后实现其中的如下方法:
public class XXX implements ShardingKeyGenerator {
@Override
public Comparable<?> generateKey() {
// 实现自定义主键生成规则,自定义实现
return null;
}
@Override
public String getType() {
// 指定主键生成的类型,对应到sharding-jdbc分片规则中的defaultKeyGenerator.type或者keyGenerator.type的值
return null;
}
@Override
public Properties getProperties() {
return null;
}
@Override
public void setProperties(Properties properties) {
}
}
通过查看sharding-jdbc源码中主键生成策略类的引用,我们发现sharding-jdbc利用了spi机制来支持用户自定义主键生成策略,也就是在项目resources/META-INF/services目录下创建名为org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator的文件,文件的值就写上我们自定义主键策略的全限定类名。
二、自定义主键生成策略
(1)、自定义MyShardingKeyGenerator
自定义主键ID生成策略为:当前日期拼接上UUID随机字符串。
public final class MyShardingKeyGenerator implements ShardingKeyGenerator {
private static Logger logger = LoggerFactory.getLogger(MyShardingKeyGenerator.class);
private Properties properties = new Properties();
@Override
public Comparable<?> generateKey() {
logger.info("execute MyShardingKeyGenerator.generateKey()");
String nowDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
String uuid = UUID.randomUUID().toString();
return nowDate + uuid;
}
@Override
public String getType() {
return "MyUUID";
}
@Override
public Properties getProperties() {
return properties;
}
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
}
(2)、SPI接口配置
在Apache ShardingSphere中,很多功能实现类的加载方式是通过SPI注入的方式完成的。Service Provider Interface (SPI)是一种为了被第三方实现或扩展的API,它可以用于实现框架扩展或组件替换。
为了让用户通过实现Apache ShardingSphere提供的相应接口,动态将用户自定义的实现类加载其中,从而在保持Apache ShardingSphere架构完整性与功能稳定性的情况下,满足用户不同场景的实际需求。
在resources目录下新建META-INF文件夹,再新建services文件夹,然后新建文件的名字为org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator的文件【META-INF/services/org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator】,文件内容为自定义主键生成策略的全限定类名【org.example.shardingjdbcdemo.algorithm.MyShardingKeyGenerator】。
(3)、配置主键ID生成策略
spring:
shardingsphere:
props:
sql:
show: true # 打印具体的插入SQL
datasource:
names: ds0,ds1
ds0: # 数据源的名称
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/order_db0?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
username: root
password: "0905"
ds1: # 数据源的名称
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/order_db1?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
username: root
password: "0905"
sharding:
tables:
t_dictionary: # 全局广播表
key-generator:
column: id # 主键字段名称
type: MyUUID # 主键生成策略:MyUUID。对应自定义主键生成策略的MyShardingKeyGenerator.getType的返回值
default-data-source-name: ds0 # 默认数据源
default-table-strategy: # 默认分表策略
none:
broadcast-tables: t_dictionary # 广播表
(4)、测试数据插入
从控制台日志输出,我们也看到了,执行了自定义主键生成策略MyShardingKeyGenerator的逻辑,并且生成的ID也自动拼接了当前日期,这就是sharding-jdbc自定义主键生成策略的思路。
2023-12-21 11:02:54.518 INFO 18372 --- [ main] o.e.s.algorithm.MyShardingKeyGenerator : execute MyShardingKeyGenerator.generateKey()
2023-12-21 11:02:55.637 INFO 18372 --- [ main] ShardingSphere-SQL : Logic SQL: insert into t_dictionary(`code`, `value`) values (?, ?)
2023-12-21 11:02:55.637 INFO 18372 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@4fc165f6, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@545b5ed0), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@545b5ed0, columnNames=[code, value], insertValueContexts=[InsertValueContext(parametersCount=2, valueExpressions=[ParameterMarkerExpressionSegment(startIndex=51, stopIndex=51, parameterMarkerIndex=0), ParameterMarkerExpressionSegment(startIndex=54, stopIndex=54, parameterMarkerIndex=1), DerivedParameterMarkerExpressionSegment(super=ParameterMarkerExpressionSegment(startIndex=0, stopIndex=0, parameterMarkerIndex=2))], parameters=[type, normal])], generatedKeyContext=Optional[GeneratedKeyContext(columnName=id, generated=true, generatedValues=[20231221dbce01cc-c0c7-43b7-aa47-014c1c6ed29d])])
2023-12-21 11:02:55.638 INFO 18372 --- [ main] ShardingSphere-SQL : Actual SQL: ds0 ::: insert into t_dictionary(`code`, `value`, id) values (?, ?, ?) ::: [type, normal, 20231221dbce01cc-c0c7-43b7-aa47-014c1c6ed29d]
2023-12-21 11:02:55.638 INFO 18372 --- [ main] ShardingSphere-SQL : Actual SQL: ds1 ::: insert into t_dictionary(`code`, `value`, id) values (?, ?, ?) ::: [type, normal, 20231221dbce01cc-c0c7-43b7-aa47-014c1c6ed29d]