设计分片键(Sharding Key)是数据库分片的核心,它决定了将数据分配到不同分片的方式。一个好的分片键应该能够均衡地分布数据,避免热点问题,提高查询性能。下面将详细介绍如何设计分片键,并结合代码进行说明。

1. 选择分片键的考虑因素

  1. 唯一性和可变性:分片键应该具有唯一性或较高的离散度,避免集中在某些分片。
  2. 查询模式:根据查询模式选择合适的分片键,以优化查询性能。
  3. 数据增长:考虑数据量的增长,分片键应能支持未来的数据扩展。
  4. 均匀分布:确保数据在各个分片中均匀分布,避免某个分片成为瓶颈。

2. 常见的分片键设计

  1. 基于唯一标识符(UUID):UUID可以确保数据均匀分布,但其长度较长,存储空间较大。
  2. 基于哈希值:对某一字段(如用户ID)进行哈希运算,将数据分配到不同的分片。
  3. 基于范围:根据某一字段的值范围分片,如日期范围或地理位置范围。
  4. 联合分片键:多个字段联合作为分片键,以提高均匀性和查询性能。

3. 基于哈希值的分片键设计示例

我们以用户ID为例,设计一个基于哈希值的分片键,并结合Spring Boot和Java代码进行实现。

项目依赖

首先,确保在pom.xml中添加必要的依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
配置数据源

application.properties中配置多个数据源:

spring.datasource.primary.url=jdbc:mysql://localhost:3306/db_shard_0
spring.datasource.primary.username=root
spring.datasource.primary.password=password
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.secondary.url=jdbc:mysql://localhost:3306/db_shard_1
spring.datasource.secondary.username=root
spring.datasource.secondary.password=password
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
数据源配置类

使用Java代码配置数据源:

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DataSourceConfig {@Bean(name = "ds0")public DataSource dataSource0() {return DataSourceBuilder.create().url("jdbc:mysql://localhost:3306/db_shard_0").username("root").password("password").driverClassName("com.mysql.cj.jdbc.Driver").build();}@Bean(name = "ds1")public DataSource dataSource1() {return DataSourceBuilder.create().url("jdbc:mysql://localhost:3306/db_shard_1").username("root").password("password").driverClassName("com.mysql.cj.jdbc.Driver").build();}@Beanpublic DataSource routingDataSource(@Qualifier("ds0") DataSource ds0, @Qualifier("ds1") DataSource ds1) {AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {@Overrideprotected Object determineCurrentLookupKey() {return ShardContextHolder.getShard(); // 从上下文中获取当前分片键}};Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("ds0", ds0);targetDataSources.put("ds1", ds1);routingDataSource.setTargetDataSources(targetDataSources);routingDataSource.setDefaultTargetDataSource(ds0);return routingDataSource;}@Beanpublic JdbcTemplate jdbcTemplate(DataSource routingDataSource) {return new JdbcTemplate(routingDataSource);}
}
分片上下文

定义一个上下文来存储当前的分片信息:

public class ShardContextHolder {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setShard(String shard) {contextHolder.set(shard);}public static String getShard() {return contextHolder.get();}public static void clearShard() {contextHolder.remove();}
}
分片键设计和数据库操作

实现基于哈希值的分片键,并进行数据库操作:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;private String getShard(String userId) {int hash = userId.hashCode();int shardId = Math.abs(hash % 2); // 这里假设有2个分片return "ds" + shardId;}public void insertUser(String userId, String name, String email) {String shard = getShard(userId);ShardContextHolder.setShard(shard);String sql = "INSERT INTO users (user_id, name, email) VALUES (?, ?, ?)";jdbcTemplate.update(sql, userId, name, email);ShardContextHolder.clearShard();}public User getUser(String userId) {String shard = getShard(userId);ShardContextHolder.setShard(shard);String sql = "SELECT * FROM users WHERE user_id = ?";User user = jdbcTemplate.queryForObject(sql, new Object[]{userId}, (rs, rowNum) -> new User(rs.getString("user_id"), rs.getString("name"), rs.getString("email")));ShardContextHolder.clearShard();return user;}
}
测试

通过调用UserService中的方法进行测试:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class TestRunner implements CommandLineRunner {@Autowiredprivate UserService userService;@Overridepublic void run(String... args) throws Exception {userService.insertUser("user1", "Alice", "alice@example.com");userService.insertUser("user2", "Bob", "bob@example.com");User user1 = userService.getUser("user1");System.out.println(user1);User user2 = userService.getUser("user2");System.out.println(user2);}
}

结论

通过以上步骤,我们实现了基于哈希值的分片键设计。分片策略、数据源配置、分片上下文和数据库操作的组合,使得系统可以根据特定的分片键将数据分布到不同的物理数据库实例中,从而提升系统的性能和可扩展性。根据实际需求,还可以选择其他分片策略(如范围分片或列表分片)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86935.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86935.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86935.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汽车一键启动升级手机控车

汽车一键启动升级手机控车实现手机远程启动&#xff0c;不改变原车任何功能且全部免接线。升级后原车遥控器能在有效范围内启动车辆。移动管家手机控车一键启动系统用手机远程控制&#xff0c;完美兼容原车遥控器。支持长安、别克、宝马、奥迪等众多系列车型&#xff0c;市场99…

【开源项目】「安卓原生3D开源渲染引擎」:Sceneform‑EQR

「安卓原生3D开源渲染引擎」&#xff1a;Sceneform‑EQR 渲染引擎 “那一夜凌晨3点&#xff0c;第一次提交 PR 的手在抖……”——我深刻体会这种忐忑与激动。 仓库地址&#xff1a;(https://github.com/eqgis/Sceneform-EQR)。 一、前言&#xff1a;开源对我意味着什么 DIY 的…

建造者模式 - Flutter中的乐高大师,优雅组装复杂UI组件!

痛点场景&#xff1a;复杂的对话框配置 假设你需要创建一个多功能对话框&#xff1a; CustomDialog(title: 警告,content: 确定要删除吗&#xff1f;,titleStyle: TextStyle(fontSize: 20, color: Colors.red),contentStyle: TextStyle(fontSize: 16),backgroundColor: Color…

基于Java+Spring Boot的大学校园生活信息平台

源码编号&#xff1a;S559 源码名称&#xff1a;基于Spring Boot的大学校园生活信息平台 用户类型&#xff1a;双角色&#xff0c;用户、管理员 数据库表数量&#xff1a;17 张表 主要技术&#xff1a;Java、Vue、ElementUl 、SpringBoot、Maven 运行环境&#xff1a;Wind…

C# .NET Framework 中的高效 MQTT 消息传递

介绍&#xff1a; 在当今互联互通的世界里&#xff0c;设备之间高效可靠的通信至关重要。MQTT&#xff08;消息队列遥测传输&#xff09;就是为此而设计的轻量级消息传递协议。本文将探讨 MQTT 是什么、它的优势以及如何在 .NET 框架中设置和实现它。最后&#xff0c;您将对 M…

nn.Embedding 和 word2vec 的区别

理解它们的关键在于​​区分概念层级和职责​​。 可以将它们类比为&#xff1a; ​​word2vec&#xff1a;​​ 一个​​专门制作高质量词向量模型的“工厂”​​。​​nn.Embedding&#xff1a;​​ 一个​​可存储、查找并训练词向量的“智能储物柜”​​&#xff08;作为…

华为云Flexus+DeepSeek征文|​​华为云ModelArts Studio大模型 + WPS:AI智能PPT生成解决方案​

引言&#xff1a;告别繁琐PPT制作&#xff0c;AI赋能高效办公 ​​ 在商业汇报、学术研究、产品发布等场景中&#xff0c;制作专业PPT往往需要耗费大量时间进行内容整理、逻辑梳理和视觉美化。​​华为云ModelArts Studio大模型​​与​​WPS​​深度结合&#xff0c;推出AI-P…

【连接redis超时】

报错 客户端输出缓冲区超限 Client … scheduled to be closed ASAP for overcoming of output buffer limits 表示这些客户端&#xff08;通过 psubscribe 命令进行发布订阅操作&#xff09;的输出缓冲区超过了 Redis 配置的限制&#xff0c;Redis 会关闭这些客户端连接来避免…

PHP「Not enough Memory」实战排错笔记

目录 PHP「Not enough Memory」实战排错笔记 1. 背景 2. 快速定位 3. 为什么 5 MB 的图片能耗尽 128 MB&#xff1f; 3.1 粗略估算公式&#xff08;GD&#xff09; 4. 实际峰值监控 5. 解决过程 6. 最佳实践与防御措施 7. 总结 PHP「Not enough Memory」实战排错笔记 —…

Java垃圾回收机制和三色标记算法

一、对象内存回收 对于对象回收&#xff0c;需要先判断垃圾对象&#xff0c;然后收集垃圾。 收集垃圾采用垃圾收集算法和垃圾收集器。 判断垃圾对象&#xff0c;通常采用可达性分析算法。 引用计数法 每个对象设置一个引用计数器。每被引用一次&#xff0c;计数器就加1&am…

基于python网络数据挖掘的二手房推荐系统

基于网络数据挖掘的二手房推荐系统设计与实现 【摘要】 随着互联网技术在房地产行业的深入应用&#xff0c;线上房源信息呈爆炸式增长&#xff0c;给购房者带来了信息过载的挑战。为了提升二手房筛选的效率与精准度&#xff0c;本文设计并实现了一个基于网络数据挖掘的二手房推…

Java + 阿里云 Gmsse 实现 SSL 国密通信

前言 解决接口或页面仅密信浏览器&#xff08;或 360 国密浏览器&#xff09;能访问的问题 测试页面 测试网站-中国银行&#xff1a;https://ebssec.boc.cn/boc15/help.html 使用其他浏览器&#xff08;google&#xff0c;edge等&#xff09;打开 使用密信浏览器打开 解决…

国产数据库分类总结

文章目录 一、华为系数据库1. 华为 GaussDB 二、阿里系数据库1. 阿里云 OceanBase2. PolarDB&#xff08;阿里云自研&#xff09; 三、腾讯系数据库1. TDSQL&#xff08;腾讯云&#xff09;2. TBase&#xff08;PostgreSQL增强版&#xff09; 四、传统国产数据库1. 达梦数据库&…

解密闭包:函数如何记住外部变量

&#x1f9e0; 什么是闭包&#xff1f; 闭包是一个函数对象&#xff0c;它不仅记住它的代码逻辑&#xff0c;还记住了定义它时的自由变量&#xff08;即非全局也非局部&#xff0c;但被内部函数引用的变量&#xff09;。即使外部函数已经执行完毕&#xff0c;这些自由变量的值…

I2C协议详解及STM32 HAL库硬件I2C卡死问题分析

一、I2C协议详解 1. I2C协议概述 Inter-Integrated Circuit (I2C) 是由 Philips 半导体&#xff08;现 NXP 半导体&#xff09;于 1980 年代设计的一种同步串行通信总线协议。该协议采用半双工通信模式&#xff0c;支持多主从架构&#xff0c;专为短距离、低速率的芯片间通信…

HTTP协议-后端接收请求

起因就是不知道post这个请求体中这些格式有什么区别&#xff0c;后端又怎么去接收这些不同格式的内容 Get请求 get请求是比较简单的一类 正常的直接用参数接收&#xff08;不写的话名字要匹配&#xff09;或者RequestParam都可以接收&#xff0c;用对象绑定也可以 resultful…

HTML5 实现的圣诞主题网站源码,使用了 HTML5 和 CSS3 技术,界面美观、节日氛围浓厚。

以下是一个 HTML5 实现的圣诞主题网站源码&#xff0c;使用了 HTML5 和 CSS3 技术&#xff0c;界面美观、节日氛围浓厚。它包括&#xff1a; 圣诞树动画 &#x1f384;雪花飘落特效 ❄️圣诞祝福语 &#x1f381;响应式布局&#xff0c;适配移动端 你可以将代码保存为 index.…

Spring Cloud Bus 和 Spring Cloud Stream

Spring Cloud Bus 和 Spring Cloud Stream 都是 Spring Cloud 生态中的消息通信组件&#xff0c;但它们的定位和使用场景有显著区别&#xff1a; 1. Spring Cloud Bus 核心定位&#xff1a;分布式系统的消息广播&#xff08;配置刷新、事件传播&#xff09;。 典型场景&#x…

磁悬浮轴承位移信号的高精度估计:卡尔曼滤波算法深度解析

无需位移传感器,滤波算法如何实现微米级精度? 磁悬浮轴承作为革命性的非接触式支承技术,凭借无磨损、无需润滑、高转速等优势,在飞轮储能、高速电机、人工心脏泵和航空航天领域获得了广泛应用。其核心控制依赖于对转子位移信号的高精度实时检测,传统电涡流传感器虽能提供位…

DAY 43 预训练模型

目录 一、预训练的概念 二、 经典的预训练模型 2.1 CNN架构预训练模型 2.2 Transformer类预训练模型 2.3 自监督预训练模型 三、常见的分类预训练模型介绍 3.1 预训练模型的发展史 3.2 预训练模型的训练策略 知识点回顾&#xff1a; 预训练的概念常见的分类预训练模型图像…