当前位置: 首页 > news >正文

项目的一些难点

1.不用redis?分布式锁,如何防止用户重复点击?

1.乐观锁

乐观锁是一种在数据库层面上避免并发冲突的机制。它通常通过在数据库记录中添加一个版本号(或时间戳)来实现。每次更新记录时,都会检查版本号是否与数据库中的版本号匹配,如果匹配,则更新数据并将版本号加一。这确保了在更新期间没有其他操作更改了记录。

  • 应用场景:适用于更新操作并不频繁,且冲突概率较低的场景

代码实现:

//实体类:注意@Version注解
@Entity
@Table(name = "form_submissions")
public class FormSubmission {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "user_id")private Long userId;@Column(name = "form_data")private String formData;@Column(name = "version")@Versionprivate int version;// 构造函数、Getter和Setter略去
}//业务层
@Service
public class FormSubmissionService {@Autowiredprivate FormSubmissionRepository repository;@Transactionalpublic String submitForm(Long userId, String formData) {Optional<FormSubmission> existingSubmission = repository.findById(userId);FormSubmission submission;if (existingSubmission.isPresent()) {// 更新现有记录submission = existingSubmission.get();submission.setFormData(formData);} else {// 创建新的记录submission = new FormSubmission();submission.setUserId(userId);submission.setFormData(formData);submission.setVersion(0); // 或根据需要设置初始版本号}try {repository.save(submission);return "表单提交成功。";} catch (org.springframework.orm.ObjectOptimisticLockingFailureException e) {// 捕获乐观锁异常,处理冲突return "提交失败,请不要重复提交。";}}
}//没有注解的时候sql层
UPDATE form_submissions
SET form_data = '新的表单数据', version = version + 1
WHERE id = ? AND version = ?;

2.数据库悲观锁

悲观锁通常通过数据库提供的锁机制实现,如 SQL 的 SELECT FOR UPDATE 语句,这会锁定被选中的数据库行,直到事务完成。这种方法适用于高冲突环境,因为它会阻止其他任何尝试修改这些行的操作。

  • 应用场景:适用于更新操作频繁,且冲突概率高的场景。

代码实现:

@Service
public class FormSubmissionService {@Autowiredprivate FormSubmissionRepository repository;@Transactionalpublic boolean submitForm(Long userId, String formData) {Optional<FormSubmission> existingSubmission = repository.findByUserIdForUpdate(userId);if (existingSubmission.isPresent()) {// 存在记录,处理重复提交逻辑return false;} else {// 不存在记录,保存新的表单提交FormSubmission submission = new FormSubmission();submission.setUserId(userId);submission.setFormData(formData);repository.save(submission);return true;}}
}//sql层代码
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT fs FROM FormSubmission fs WHERE fs.userId = :userId")
Optional<FormSubmission> findByUserIdForUpdate(@Param("userId") Long userId);

3.基于内存的锁

如果你的应用程序运行在单个实例或能够使用共享内存系统(如 Hazelcast、Apache Ignite),可以使用内存中的数据结构来实现锁逻辑。例如,使用一个全局哈希表存储正在进行的操作的标识符,来防止重复。

  • 应用场景:适用于单实例应用或者有共享内存系统的分布式应用。
@Service
public class FormSubmissionService {private final Map<Long, Lock> userLocks = new HashMap<>();public String submitForm(Long userId, String formData) {Lock lock = userLocks.computeIfAbsent(userId, k -> new ReentrantLock());if (lock.tryLock()) {try {// 模拟表单处理逻辑Thread.sleep(1000); // 假设处理需要一段时间System.out.println("表单数据处理: " + formData);return "表单提交成功。";} catch (InterruptedException e) {Thread.currentThread().interrupt();return "表单处理中断。";} finally {lock.unlock();}} else {return "正在处理中,请不要重复提交。";}}
}

4.应用程序级的去重逻辑

在应用程序级别实现去重逻辑,例如,通过在前端禁用提交按钮,直到请求完成,或者在后端设置一个短暂的时间窗口,在这个窗口内忽略来自同一用户的重复请求。

  • 应用场景:适用于需要快速实现且冲突概率不高的场景。

5.唯一标识符

要求客户端在请求时生成一个唯一的标识符(如 UUID),并在服务器端检查这个标识符是否已经被处理。这个标识符可以存储在内存或数据库中,以确保每个请求只被处理一次。

  • 应用场景:适合于任何需要确保请求唯一性的场景,特别是在分布式系统中。

代码实现:

@Service
public class RequestService {@Autowiredprivate RequestIdRepository requestIdRepository;public boolean processRequest(String requestId) {// 检查请求ID是否已存在Optional<RequestId> existingRequestId = requestIdRepository.findById(requestId);if (existingRequestId.isPresent()) {// 请求ID已存在,拒绝重复处理return false;} else {// 请求ID不存在,处理请求RequestId newRequestId = new RequestId();newRequestId.setId(requestId);requestIdRepository.save(newRequestId); // 保存请求ID标记为已处理// 在这里执行其他请求处理逻辑...return true;}}
}

在这个实现中,客户端需要生成一个 UUID 并在每次请求时发送这个 UUID 作为 `requestId` 参数。服务器通过检查这个 `requestId` 是否已经存在于 `request_ids` 表中来防止重复处理相同的请求。这种方法适用于分布式系统中确保请求的唯一性,有效地防止了用户因为多次点击导致的重复请求问题。

2.Cookie、Session、Token、JWT之间的区别

傻傻分不清之 Cookie、Session、Token、JWT - 掘金

3.40亿个QQ号,限制1G内存,如何去重?

1.位图(Bitmap)

图是一种非常高效的数据结构,通过使用1个位来标记某个元素是否存在。假设我们使用40亿位(或者说500MB)的内存空间,就可以表示40亿个不同的QQ号。

  1. 初始化位图:创建一个大约500MB大小的位图,每个位对应一个可能的QQ号。由于QQ号可能不会完全连续,我们需要根据实际QQ号的范围来调整位图的大小。

  2. 标记QQ号:遍历所有QQ号,对每个QQ号,计算它在位图中的位置,并将相应的位设置为1。

  3. 去重:再次遍历QQ号,通过检查位图中对应位的值,可以判断一个QQ号是否已经出现过。

这种方法的缺点是,如果QQ号的范围非常大,位图的大小可能会超出1GB的内存限制。

代码实现:

public class Bitmap {private byte[] bits;public Bitmap(int size) {bits = new byte[(size + 7) / 8];}public void set(int k) {int byteIndex = k / 8;int bitIndex = k % 8;bits[byteIndex] |= (1 << bitIndex);}public boolean get(int k) {int byteIndex = k / 8;int bitIndex = k % 8;return (bits[byteIndex] & (1 << bitIndex)) != 0;}
}// 假设QQ号范围在一定区间内,这里简化处理
Bitmap bitmap = new Bitmap(4000000000); // 大约需要500MB内存
// 设置QQ号
bitmap.set(qqNumber);
// 检查QQ号是否已存在
boolean exists = bitmap.get(qqNumber);

2.布隆过滤器(Bloom Filter)

布隆过滤器是一种空间效率极高的概率型数据结构,用于判断一个元素是否在集合中:

  1. 初始化布隆过滤器:根据数据量和可接受的误判率初始化布隆过滤器。

  2. 添加元素:遍历QQ号,将每个QQ号添加到布隆过滤器中。

  3. 预过滤:再次遍历QQ号,首先使用布隆过滤器检查是否可能已经存在。由于布隆过滤器存在一定的误判率,对于判断存在的元素,需要进一步确认。

布隆过滤器适用于快速预过滤,减少需要进一步处理的数据量,但需要额外的机制来处理误判。

public class BloomFilter {private BitSet hashes;private int size;public BloomFilter(int size) {this.size = size;this.hashes = new BitSet(size);}private int hash(Object obj, int k) {return Math.abs(obj.hashCode() * k) % size;}public void add(Object obj) {for (int k = 1; k <= 3; k++) { // 使用3个不同的哈希函数int hash = hash(obj, k);hashes.set(hash);}}public boolean mightContain(Object obj) {for (int k = 1; k <= 3; k++) {int hash = hash(obj, k);if (!hashes.get(hash)) {return false; // 如果有一个位不是1,那么对象肯定没有添加}}return true; // 可能包含}
}// 使用
BloomFilter filter = new BloomFilter(100000000); // 需要调整大小以适应内存限制
filter.add(qqNumber);
boolean mightExist = filter.mightContain(qqNumber);

相关文章:

项目的一些难点

1.不用redis?分布式锁&#xff0c;如何防止用户重复点击&#xff1f; 1.乐观锁 乐观锁是一种在数据库层面上避免并发冲突的机制。它通常通过在数据库记录中添加一个版本号&#xff08;或时间戳&#xff09;来实现。每次更新记录时&#xff0c;都会检查版本号是否与数据库中的…...

Kubernetes 卷存储 NFS | nfs搭建配置 原理介绍 nfs作为存储卷使用

1、NFS介绍 NFS&#xff08;Network File System&#xff09;是一种分布式文件系统协议&#xff0c;允许客户端远程访问服务器上的文件&#xff0c;实现数据共享。它整合多个存储设备为统一文件系统&#xff0c;方便数据存储和管理&#xff0c;支持负载均衡和故障转移&#xf…...

开启智能互动新纪元——ChatGPT提示词工程的引领力

目录 提示词工程的引领力 高效利用ChatGPT提示词方法 提示词工程的引领力 近年来&#xff0c;随着人工智能技术的迅猛发展&#xff0c;ChatGPT提示词工程正逐渐崭露头角&#xff0c;为智能互动注入了新的活力。这一技术的引入&#xff0c;使得人机交流更加流畅、贴近用户需求&…...

ElasticSearch语法

Elasticsearch 概念 入门学习: Index索引>MySQL 里的表(table)建表、增删改查(查询需要花费的学习时间最多)用客户端去调用 ElasticSearch(3 种)语法:SQL、代码的方法(4 种语法) ES 相比于 MySQL&#xff0c;能够自动帮我们做分词&#xff0c;能够非常高效、灵活地查询内…...

SMT贴片加工厂需要哪些加工资料

SMT贴片加工中在评估报价的时候需要给到SMT贴片加工厂以下资料&#xff0c;以便工程师和采购进行工艺和报价评估。 在SMT加工中如果需要供应商提供一站式的加工服务&#xff0c;那么在前期就需要更频繁的沟通和配合&#xff0c;包工包料服务是需要PCB制板资料和制板说明、BOM清…...

jmeter下载base64加密版pdf文件

一、何为base64加密版pdf文件 如下图所示&#xff0c;接口jmeter执行后&#xff0c;返回一串包含大小写英文字母、数字、、/、的长字符串&#xff0c;直接另存为pdf文件后&#xff0c;文件有大小&#xff0c;但是打不开&#xff1b;另存为doc文件后&#xff0c;打开可以看到和…...

【regex】正则表达式

集合 [0-9.] [0-9.\-] 例子 正则表达式&#xff0c;按照规则写&#xff0c;写的时候应该不算困难&#xff0c;但是可读性差 不同语言中regex会有微小的差异 vim 需要转义&#xff0c; perl/python中不需要转义 锚位 \b am\b i am 命名 / 命名捕获组 ( 捕获组&#xff08;…...

78.Spring和SpringBoot的关系和区别?

一、Spring和SpringBoot的关系和区别 SpringBoot是Spring生态的产品。 Spring Framework是一个容器框架 SpringBoot 它不是一个框架、它是一个可以快速构建基于Spring的脚手架(里面包含了Spring和各种框架&#xff09;&#xff0c;为开发Spring生态其他框架铺平道路&#xff0…...

【PyTorch][chapter 17][李宏毅深度学习]【无监督学习][ Auto-encoder]

前言&#xff1a; 本篇重点介绍AE&#xff08;Auto-Encoder&#xff09; 自编码器。这是深度学习的一个核心模型. 自编码网络是一种基于无监督学习方法的生成类模型,自编码最大特征输出等于输入 Yann LeCun&Bengio, Hinton 对无监督学习的看法. 目录&#xff1a; AE 模型原…...

Modern C++ std::variant的实现原理

前言 std::variant是C17标准库引入的一种类型&#xff0c;用于安全地存储和访问多种类型中的一种。它类似于C语言中的联合体&#xff08;union&#xff09;&#xff0c;但功能更为强大。与联合体相比&#xff0c;std::variant具有类型安全性&#xff0c;可以判断当前存储的实际…...

⭐北邮复试刷题LCR 018. 验证回文串__双指针 (力扣119经典题变种挑战)

LCR 018. 验证回文串 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s “A man, a plan, a canal: Panama” 输出: true 解释…...

C++面试:数据库的权限管理数据库的集群和高可用

目录 一、数据库的权限管理 1. 用户和角色管理 用户管理 实例举例&#xff08;以MySQL为例&#xff09;&#xff1a; 角色管理 实例举例&#xff08;以MySQL为例&#xff09;&#xff1a; 总结 2. 权限和授权 用户和角色管理 用户管理 角色管理 权限和授权 权限 授…...

个人搭建部署gpt站点

2024搭建部署gpt 参照博客 https://cloud.tencent.com/developer/article/2266669?areaSource102001.19&traceIdRmFvGjZ9BeaIaFEezqQBj博客核心点 准备好你的 OpenAI API Key; 点击右侧按钮开始部署&#xff1a; Deploy with Vercel&#xff0c;直接使用 Github 账号登…...

samber/lo 库的使用方法: condition

samber/lo 库的使用方法&#xff1a; condition samber/lo 是一个 Go 语言库&#xff0c;使用泛型实现了一些常用的操作函数&#xff0c;如 Filter、Map 和 FilterMap。汇总目录页面 这个库函数太多&#xff0c;因此我决定按照功能分别介绍&#xff0c;本文介绍的是 samber/l…...

Chrome插件精选 — 缓存清理

Chrome实现同一功能的插件往往有多款产品&#xff0c;逐一去安装试用耗时又费力&#xff0c;在此为某一类型插件挑选出比较好用的一款或几款&#xff0c;尽量满足界面精致、功能齐全、设置选项丰富的使用要求&#xff0c;便于节省一个个去尝试的时间和精力。 1. Chrome清理大师…...

Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录 一、介绍二、方案介绍三、Redis Docker部署四、SpringBoot3 Base代码1. 依赖配置2. 基本代码 五、缓存优化代码1. 校验机制2. 布隆过滤器3. 逻辑优化 一、介绍 当一种请求&#xff0c;总是能越过缓存&#xff0c;调用数据库&#xff0c;就是缓存穿透。 比如当请求一…...

每日shell脚本之超级整合程序3.0

每日shell脚本之超级整合程序3.0 本期带来之前的升级版2.0整合脚本程序,学习工作小利器,同时模块化构建方便二次开发。 上图 上源码 #!/usr/bin/bash # *******************************************# # * CDDN : M乔木 # # * qq邮箱 …...

Docker介绍与使用

Docker介绍与使用 目录&#xff1a; 一、Docker介绍 1、Docker概述与安装 2、Docker三要素 二、Docker常用命令的使用 1、镜像相关命令 2、容器相关命令 三、Docker实战之下载mysql、redis、zimg 一、Docker介绍 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包…...

Gin框架: 使用go-ini配置参数与不同环境下的配置部署

关于 INI 配置文件与go-ini 1 &#xff09;概述 在INI配置文件中可以处理各种数据的配置INI文件是一种简单的文本格式&#xff0c;常用于配置软件的各种参数go-ini 是地表 最强大、最方便 和 最流行 的 Go 语言 INI 文件操作库 Github 地址&#xff1a;https://github.com/go-…...

探究网络工具nc(netcat)的使用方法及安装步骤

目录 &#x1f436;1. 什么是nc&#xff08;netcat&#xff09;&#xff1f; &#x1f436;2. nc&#xff08;netcat&#xff09;的基本使用方法 2.1 &#x1f959;使用 nc 进行端口监听 2.2 &#x1f959;使用 nc 进行端口扫描 2.3 &#x1f959;使用 Netcat 进行文件传输…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

GAN模式奔溃的探讨论文综述(一)

简介 简介:今天带来一篇关于GAN的,对于模式奔溃的一个探讨的一个问题,帮助大家更好的解决训练中遇到的一个难题。 论文题目:An in-depth review and analysis of mode collapse in GAN 期刊:Machine Learning 链接:...

从零手写Java版本的LSM Tree (一):LSM Tree 概述

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…...