1.ShardingSphere 下的Sharding-JDBC简介
2.分库分表和Sharding-Jdbc常⻅概念术语介绍
3.Sharding-Jdbc实现分库分表实战
4.分库分表暴露的问题-ID冲突及解决
5.分布式 ID ⽣成算法Snowflake原理
6.Snowflake自定义wrokId实战
分库分表和Sharding-Jdbc常⻅概念术语介绍
Sharding-Jdbc实现分库分表实战
先来建两个表
CREATE TABLE `traffic_0` ( `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, `account_no` bigint DEFAULT NULL COMMENT '账号') ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;CREATE TABLE `traffic_1` ( `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, `account_no` bigint DEFAULT NULL COMMENT '账号') ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;依赖
org.apache.shardingsphere sharding-jdbc-spring-boot-starter 4.1.1 mybatis-plus
com.baomidou mybatis-plus-boot-starter 3.4.0 设置配置:
shardingsphere: datasource: ds0: connectionTimeoutMilliseconds: 30000 driver-class-name: com.mysql.cj.jdbc.Driver idleTimeoutMilliseconds: 60000 jdbc-url: jdbc:mysql://127.0.0.1:3306/user_account?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true maintenanceIntervalMilliseconds: 30000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 minPoolSize: 50 password: 123456 type: com.zaxxer.hikari.HikariDataSource username: root names: ds0 props: # 打印执⾏的数据库以及语句 sql: show: true sharding: tables: traffic: actual-data-nodes: ds0.traffic_$->{ 0..1} # ⽔平分表策略+⾏表达式分⽚ table-strategy: inline: algorithm-expression: traffic_$->{ account_no % 2 } sharding-column: account_no对应实体类
只需要有account_no就行,因为分片策略需要使用,其他字段无所谓
测试:
@RunWith(SpringRunner.class)@SpringBootTest(classes = AccountApplication.class)@Slf4jpublic class trafficTest { @Resource private TrafficMapper trafficMapper; Random random = new Random(); @Test public void insert(){ for(int i=0;i<10;i++){ TrafficDO trafficDO = new TrafficDO(); trafficDO.setAccountNo(Long.valueOf(random.nextInt(100))); ; trafficMapper.insert(trafficDO); } }}运行后使用navicat可视化工具查看如下:
根据我们的分区策略,%2来选择插入那个表
但是有个问题
两个表 主键id互相重复
上面分库分表暴露的问题-ID冲突
解决方法: 分布式id⽣成
分布式id生成需求
分布式 ID ⽣成算法Snowflake原理
什么是雪花算法Snowflake
twitter⽤scala语⾔编写的⾼效⽣成唯⼀ID的算法
优点
⽣成的ID不重复
算法性能⾼
基于时间戳,基本保证有序递增
雪花算法⽣成的数字,long类,所以就是8个byte,64bit表示的值 -9223372036854775808(-2的63次⽅) ~9223372036854775807(2的63次⽅-1)
⽣成的唯⼀值⽤于数据库主键,不能是负数,所以值为0~9223372036854775807(2的63次⽅-1)
使用Sharding-Jdbc配置⽂件,设置主键生成使用雪花算法,配置变为如下
shardingsphere: datasource: ds0: connectionTimeoutMilliseconds: 30000 driver-class-name: com.mysql.cj.jdbc.Driver idleTimeoutMilliseconds: 60000 jdbc-url: jdbc:mysql://127.0.0.1:3306/user_account?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true maintenanceIntervalMilliseconds: 30000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 minPoolSize: 50 password: 123456 type: com.zaxxer.hikari.HikariDataSource username: root names: ds0 props: # 打印执⾏的数据库以及语句 sql: show: true sharding: tables: traffic: actual-data-nodes: ds0.traffic_$->{ 0..1} # ⽔平分表策略+⾏表达式分⽚ table-strategy: inline: algorithm-expression: traffic_$->{ account_no % 2 } sharding-column: account_no #id⽣成策略 key-generator: column: id props: worker: id: 0 #id⽣成策略 type: SNOWFLAKE再次运行我们之前编写的测试代码,可在数据库中看到如下结果:
好了,主键id不一样了,我们分布式下我们还要保证workid不同和account_no不同,于是我们需要编写以下代码
@Configuration@Slf4jpublic class SnowFlakeWordIdConfig { /** * 动态指定sharding jdbc 的雪花算法中的属性work.id属 性 * 通过调⽤System.setProperty()的⽅式实现,可⽤容器的 id 或者机器标识位 * workId最⼤值 1L << 100,就是1024,即 0<= workId < 1024 * {@link SnowflakeShardingKeyGenerator#getWorkerId()} * */ static { try { InetAddress ip4 = Inet4Address.getLocalHost(); String addressIp = ip4.getHostAddress(); String workerId = (Math.abs(addressIp.hashCode())%1024)+""; System.setProperty("workerId", workerId); } catch (UnknownHostException e) { log.error("生成雪花id出错{}",e); } }}并将配置中的
props: worker: id: 0 #id⽣成策略 type: SNOWFLAKE 改为 props: worker: id: ${workerId} #id⽣成策略 type: SNOWFLAKE同样使用雪花算法生成acoount_no
代码:
public class IDUtil { private static SnowflakeShardingKeyGenerator shardingKeyGenerator = new SnowflakeShardingKeyGenerator(); /** * 雪花算法⽣成器,配置workId,避免重复 * * 10进制 654334919987691526 * 64位 * 0000100100010100101010100010010010010110000000000000 * 000000000110 *
* * @return */ public static Comparable<?> geneSnowFlakeID() { return shardingKeyGenerator.generateKey(); }}
将测试代码中的随机生成换位idutil的生成即可
@Test public void insert(){ for(int i=0;i<10;i++){ TrafficDO trafficDO = new TrafficDO(); //trafficDO.setAccountNo(Long.valueOf(random.nextInt(100))); trafficDO.setAccountNo(Long.valueOf(IDUtil.geneSnowFlakeID().toString())); trafficMapper.insert(trafficDO); } }}运行后,如下:
本篇完!
| 留言与评论(共有 0 条评论) “” |