分布式项目使用Redis实现数据库对象自增主键ID
hello。大家好,我是灰小猿,一个超会写bug的程序猿!
在分布式项目中,数据表的主键ID一般可能存在于UUID或自增ID这两种形式,UUID好理解而且实现起来也最容易,但是缺点就是数据表中的主键ID是32位的字符串,在大数据查询等情况下性能会相对比较差,所以在需求允许的情况下,我们通常会优先考虑使用自增ID来代替UUID使用。
在分布式项目中如果你的数据表的主键ID是自增ID,那么常见的生成对象主键ID的方式有:
-
雪花算法
-
优点:实现简单
-
缺点:生成ID较长、生成ID不连续,会造成ID浪费
-
-
采用框架自带的ID生成器,如MybatisPlus的@AutoID
-
优点:依赖框架,实现简单
-
缺点:无法在插入对象前获取到对象的主键ID
-
-
采用Redis缓存生成主键ID等
-
优点:生成的ID连续,数据在表中的可读性好
-
缺点:借助Redis缓存,实现相比前两种较复杂
-
通过雪花算法生成对象主键ID的方式我们在之前的文章中已经介绍过了,这篇文章我们主要介绍如何通过Redis来实现生成对象自增ID的方法。
1、缓存实现原理
通过Redis实现对象自增ID的方式,主要是通过Redis的INCR 和 INCRBY 命令来对键值进行递增操作,从而实现计数器的功能,主要原因是Redis 是单线程模型,所有命令都是原子操作,不会发生竞态条件,
在使用时要留意以下特点与注意事项
-
原子性:
INCR、INCRBY和INCRBYFLOAT命令都是原子性的,这意味着如果多个客户端同时执行这些命令,Redis 会保证每个命令的执行不会发生竞态条件。 -
数据类型要求:这些命令要求操作的值是整数(
INCR和INCRBY)或浮点数(INCRBYFLOAT)。如果键对应的值不是数值类型,Redis 会返回错误。 -
性能:Redis 是单线程的,所有命令都是原子操作,因此在高并发环境下执行这些命令时,性能表现非常好。
-
键不存在的情况:如果执行
INCR或INCRBY时,键不存在,Redis 会自动创建这个键并初始化其值为 0,然后进行递增。
2、Redis工具类实现ID自动生成
了解到通过Redis实现的原理之后,就是如何设计缓存以保证每张表的数据之间不会相互影响,
以user表为例,对应的model为UserModel,那么我们就可以将model名称作为key,当前已有的最大的ID作为value来进行存储,因为每一张表对应的model名称都是不一样的,所以这里一定不会出现key重复的情况,
下面是一些在Redis中生成和获取对象自增ID的工具方法,方便新建对象时直接调用
@Component("redisUtils")
@RequiredArgsConstructor
@Slf4j
public class RedisUtils implements InitializingBean {private final StringRedisTemplate stringRedisTemplate;private static RedisUtils redisUtils;@Overridepublic void afterPropertiesSet() {redisUtils = this;}/*** 获取自增ID*/public static <T> Integer getIncr(Class<T> tClass) {try {String key = tClass.getName();Long increment = redisUtils.stringRedisTemplate.opsForValue().increment(key, 1);return Math.toIntExact(increment);} catch (Exception e) {e.printStackTrace();throw new RedisSystemException(e.getMessage(), e);}}/*** 获取自增ID,指定递增长度,用于批量创建对象时,只请求一次Redis* 如批量创建五个对象,delta等于5*/public static <T> Integer getIncr(Class<T> tClass, int delta) {try {String key = tClass.getName();Long increment = redisUtils.stringRedisTemplate.opsForValue().increment(key, delta);return Math.toIntExact(increment);} catch (Exception e) {e.printStackTrace();throw new RedisSystemException(e.getMessage(), e);}}/*** 缓存预热,用于项目启动时初始化Redis中各个表的最大ID*/public static <T> long incrPreheat(Class<T> tClass, Long maxValue) {if (maxValue == null) {maxValue = 0L;}if (maxValue < 0) {//异常抛出,预热的初始值不能小于0}Integer incr = getIncr(tClass);if (maxValue <= incr) {return incr;}return getIncr(tClass, (int) (maxValue - incr));}
}
解释:InitializingBean是Spring提供的拓展性接口,InitializingBean接口为bean提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。
3、缓存预热
缓存预热是指在项目启动时,将每一张表当前最大的主键ID预先加载到Redis中,这样在后面使用的时候,就可以直接从Redis中获取下一次ID即可,不需要再去访问数据库查询最大ID,缓存预热一般会建立在Redis专门的初始化类中,以便在启动项目时可以运行该类,具体如下:
/*** 缓存预热** @author hxy*/
@Component
@DependsOn("redisUtils")
@RequiredArgsConstructor
public class RedisInit {private final UserMapper userMapper;/*** 获取每一张表中当前的最大ID,然后预热到redis中*/@PostConstructpublic void init() {RedisUtils.incrPreheat(UserModel.class, userMapper.maxId());}
}
解释:@DependsOn注解可以定义在类和方法上,意思是我这个组件要依赖于另一个组件,也就是说被依赖的组件会比该组件先注册到IOC容器中。
解释:@PostConstruct注解
在Java中,@PostConstruct注解,通常用于标记一个方法,它表示该方法在类实例化之后(通过构造函数创建对象之后)立即执行。
加上@PostConstruct注解的方法会在对象的所有依赖项都已经注入完成之后执行。通过使用@PostConstruct注解,我们可以确保在对象完全创建和初始化之后才执行这些操作。这个注解通常用在依赖注入(Dependency Injection)的框架中,例如Spring。
@PostConstruct 注解可以用在任何类的方法上,但它最常用于标记在 Spring Framework 中的 Bean 类中的初始化方法。
4、model层封装调用
在实例化一个model对象的时候,要将model的主键ID进行赋值,这个时候就要从Redis中获取到当前对象应该对应的主键ID,我们可以在model类中构建一个newInstance方法或有参构造,来专门的生成需要赋值主键ID的对象,在方法中调用redis工具类的getIncr方法,获取到最新最小未使用的主键ID并赋值给新建的model即可。
@Getter
@Setter
public class UserModel {private Integer id;private String name;private Integer age;private String tel;public UserModel() {}/*** 提供一个能够生成自增ID的有参构造,需要生成自增ID时调用*/public UserModel(boolean autoId) {if (autoId) {this.id = RedisUtils.getIncr(UserModel.class);}}
}
如果你是需要批量创建对象并且给对象赋值主键ID的情况,可以按照如下方式使用,这样可以只调用一次Redis,避免重复调用Redis影响性能。
@Service
@RequiredArgsConstructor
public class UserServiceImpl {private final UserMapper userMapper;public void batchAddUser(){int addNumber = 10;//提前生成自定跨度的ID,比如之前最大ID是6,获取后得到的incr是16Integer incr = RedisUtils.getIncr(UserModel.class, addNumber);List<UserModel> userModels = new ArrayList<>();for (int i = 0; i < addNumber; i++) {UserModel userModel = new UserModel();//每一个主键ID依次递减使用userModel.setId(incr--);userModels.add(userModel);}userMapper.insertBatch(userModels);}
}
至此,通过Redis来获取对象自增ID的方法已经完成,如果在使用过程中有其他场景需求,可以对redisUtils中的方法进行拓展即可。
我是灰小猿,我们下期见!
相关文章:
分布式项目使用Redis实现数据库对象自增主键ID
hello。大家好,我是灰小猿,一个超会写bug的程序猿! 在分布式项目中,数据表的主键ID一般可能存在于UUID或自增ID这两种形式,UUID好理解而且实现起来也最容易,但是缺点就是数据表中的主键ID是32位的字符串&a…...
npm-运行项目报错:A complete log of this run can be found .......npm-cache_logs\
1.问题 没有找到对应的某种依赖,node_modules出现问题。 2.解决 (1)查看对应依赖是否引入或者是由于合并分支错误 引入js或依赖不存在。谨慎删除依赖包 (2)查找对应引入依赖进行安装最后解决方法-删除依赖包清除缓存 npm cache clean --force (2)重新向同事引入…...
SolarCube: 高分辨率太阳辐照预测基准数据集
太阳能作为清洁能源在减缓气候变化中的作用日益凸显,其稳定的供应对电网管理至关重要。然而,太阳辐照受云层和天气变化的影响波动较大,给光伏电力的管理带来挑战,尤其是在调度、储能和备用系统管理方面。因此,精确的太…...
华为小米苹果三星移动设备访问windows共享文件夹windows11
如果移动设备和windows电脑都在同一个局域网内,可以用移动设备访问windows11的共享文件夹 1、设置共享文件夹 2、添加everyone用户即可 3、查看ip地址 4、在华为手机上点击文件管理,里面有个网上邻居 5、正常情况下,华为手机会扫描到同一局域…...
网络安全三防指南:只防病毒不安全
5月17日,瑞星全球反病毒监测网截获一个恶性病毒,由于该病毒的破坏能力和当年著名的CIH病毒几乎完全一样,因此瑞星将该病毒命名为“新CIH”病毒。被“新CIH”感染的电脑,主板和硬盘数据将被破坏,致使电脑无法启动&#…...
论文概览 |《Urban Analytics and City Science》2023.05 Vol.50 Issue.4
本次给大家整理的是《Environment and Planning B: Urban Analytics and City Science》杂志2023年5月第50卷第4期的论文的题目和摘要,一共包括19篇SCI论文! 论文1 Data analytics and sustainable urban development in global cities 全球城市的数据…...
【ROS2】ROS2 C++版本 与 Python版本比较
ROS 系列学习教程(总目录) ROS2 系列学习教程(总目录) 目录 一、功能包的构建方式二、功能包组织结构三、代码编写四、性能与效率五、兼容性六、应用场景 目前ROS开发主要使用 C 和 Python 语言,这里会分别实现并讲解。 相较于ROS1,ROS2的 C 和 Python …...
物联网射频识别和RFID开发(一):RFID基础—概念、应用
一、RFID的发展历史 二、RFID与物联网 (一)物联网与RFID的关系 物联网的基本思想是美国麻省理工学院在1999年提出的,其核心思想是为全球每个物品提供唯一的电子标识符。这种电子标识符就是现在经常提到的“电子产品编码(Electronic Product …...
JVM:即时编译器,C2 Compiler,堆外内存排查
1,即时编译器 1.1,基本概念 常见的编译型语言如C,通常会把代码直接编译成CPU所能理解的机器码来运行。而Java为了实现“一次编译,处处运行”的特性,把编译的过程分成两部分,首先它会先由javac编译成通用的…...
webpack5 的五大核心配置(二)
webpack主要构成部分: entry 入口output 出口loaders 转化器plugins 插件mode 模式devServer 开发服务器 webpack.config.js 配置文件基本格式 module.exports{//入口文件entry:{},//出口文件output:{},//module rules loadersmodule{};//插件plugins:[],//开发…...
【查询基础】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...
git push使用
推送指定分支 将当前分支推送远程 git push origin HEAD:<branch-name> 这里的 HEAD 是一个特殊的指针,它指向当前分支的最新提交。这条命令会将当前分支的更改推送到远程的 master 分支。 示例 git push origin HEAD:main 当前分支是test,远…...
【iOS】多线程基础
【iOS】多线程基础 文章目录 【iOS】多线程基础前言进程与线程进程进程的状态进程的一个控制结构进程的上下文切换 线程为什么要用线程什么是线程线程和进程的关系线程的上下文切换 线程和进程的优缺点 小结 前言 笔者由于对于GCD不是很了解,导致了项目中网络请求哪…...
常用网站网址
目录 1.docker hub2.csdn 1.docker hub https://image.cgdcgd.cc/ 2.csdn https://www.csdn.net/ ...
go语言切片
切片 切片是一种数据结构,这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的…...
鸿蒙NEXT元服务:利用App Linking实现无缝跳转与二维码拉起
【效果】 元服务链接格式(API>12适用):https://hoas.drcn.agconnect.link/ggMRM 【参考网址】 使用App Linking实现元服务跳转:文档中心 草料二维码:草料二维码生成器 【引言】 本文将详细介绍如何使用App Lin…...
网络药理学之薛定谔Schrödinge Maestro:6、分子对接(Glide、Ligand docking)和可视化
本人是win11,薛定谔版本是12.9。 官网:https://www.schrodinger.com/ 本篇文章的示例大分子蛋白PDB ID为4KNN,小分子配体的MOL ID为MOL004004。 本文部分图源来自知乎https://zhuanlan.zhihu.com/p/416698194,推荐为原作者贡献阅读…...
已解决ModuleNotFoundError: No module named ‘selenium‘
1. 错误提示 ModuleNotFoundError: No module named selenium,这意味着你试图导入一个名为 selenium 的模块,但Python找不到这个模块 2. 解决方案 安装缺失的模块: 如果你确定模块名称正确但仍然收到这个错误,那么可能是你没有安装这个模块…...
【Maven】依赖冲突如何解决?
准备工作 1、创建一个空工程 maven_dependency_conflict_demo,在 maven_dependency_conflict_demo 创建不同的 Maven 工程模块,用于演示本文的一些点。 什么是依赖冲突? 当引入同一个依赖的多个不同版本时,就会发生依赖冲突。…...
什么是EMS
EMS是能量管理系统(Energy Management System)的缩写,是一种集成的技术解决方案,旨在帮助企业和组织更有效地管理和优化其能源使用。EMS通过收集、分析和报告能源数据来识别节能机会,并提供工具以实施改进措施。 主要…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
