深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

2024-09-08 15:28

本文主要是介绍深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理

秒杀系统是应对高并发、高压力下的典型业务场景,涉及到并发控制、库存管理、事务管理等多个关键技术点。本文将深入剖析秒杀商品业务中常见的几个核心问题,包括 AOP 事务管理、同步锁机制、乐观锁、CAS 操作,以及用户限购策略。通过这些技术的结合,确保秒杀系统在高并发场景下的稳定性和一致性。


1. AOP 代理对象与事务管理

在秒杀商品的业务中,事务管理是至关重要的环节,尤其是涉及到库存扣减和订单创建的场景。Spring 提供了 @Transactional 注解,通过 AOP(面向切面编程)实现事务管理。为了保证事务的正常执行,方法调用必须通过 Spring 的代理对象来进行

为什么需要代理对象?

Spring 的事务管理是通过 AOP 实现的,AOP 的本质是通过代理对象拦截方法调用,并在方法调用前后进行事务的开启、提交、回滚等操作。如果在同一个类中直接调用 this 方法,则不会经过代理,事务拦截器无法生效,导致事务管理失效。

解决方案

为了确保在类内部调用方法时依然通过代理对象,我们可以通过以下技术:

  1. AopContext.currentProxy():Spring 提供的 AopContext.currentProxy() 方法可以获取当前类的代理对象,确保事务正常生效。
  2. @EnableAspectJAutoProxy(exposeProxy = true):该注解的作用是暴露当前的代理对象,配合 AopContext.currentProxy() 来获取代理对象。

代码示例

synchronized (uid.toString().intern()) {// 获取当前代理对象,确保事务生效IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createOrder(productId, uid);
}

在这个场景中,我们确保通过代理对象调用 createOrder 方法,以保证事务的正确性。


2. 并发控制与锁机制

在秒杀商品业务中,确保单个用户不能在同一时刻多次请求是很重要的。为了实现这一点,我们可以使用 synchronized 锁机制,通过用户 ID 进行加锁,确保一个用户不能同时发起多次秒杀请求。

synchronized (uid.toString().intern()) 机制

  • uid.toString().intern() 方法保证相同的用户 ID 会共享同一个锁对象,intern() 会将字符串放入常量池,从而确保不同用户获得不同的锁对象,而相同用户始终使用相同的锁。
  • synchronized 锁粒度基于用户,防止同一用户并发访问,确保线程安全。

注意:这种锁机制是 JVM 层面的锁,适用于单机环境。如果是分布式部署,还需要使用 Redis 分布式锁 等手段来确保分布式环境下的并发控制。

代码示例

Long uid = UserHolder.getUser().getId();
synchronized (uid.toString().intern()) {// 秒杀业务逻辑
}

在分布式环境下,可以用 Redis 锁来代替 JVM 锁,确保分布式集群环境中的并发安全。


3. 锁包含事务,还是事务包含锁?

在秒杀业务中,锁和事务的执行顺序非常关键。通常情况下,我们希望在进入临界区(即加锁后)开启事务,确保多个操作的原子性。这意味着锁的作用是为了保证并发控制,而事务的作用是确保数据操作的原子性和一致性。

因此,锁先于事务启动,事务的所有操作都在加锁保护的代码块内执行。这样可以确保在并发情况下,事务中的操作不会出现线程安全问题。

代码示例

synchronized (uid.toString().intern()) {// 在锁内,调用带有事务的方法IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createOrder(productId, uid);
}

在这个流程中,锁保护了事务,确保同一时间只有一个用户可以创建订单,并且事务操作得到正确的执行。


4. 乐观锁、悲观锁、版本号、CAS

在秒杀场景中,库存扣减的正确性是关键问题之一。常见的解决方案包括乐观锁、悲观锁、CAS(Compare And Swap),它们各有优缺点。

  • 乐观锁:基于一种“乐观”的思想,假设不会发生冲突,因此不加锁。它通过 版本号 或其他条件进行判断。在库存扣减时,通过检查 stock > 0 或版本号的方式保证库存扣减的正确性。

    宽松的乐观锁

    UPDATE product_stock
    SET stock = stock - 1
    WHERE product_id = #{productId} AND stock > 0;
    

    严格的乐观锁

    UPDATE product_stock
    SET stock = stock - 1
    WHERE product_id = #{productId} AND stock = #{currentStock};
    

    宽松的乐观锁只要库存大于 0 就能扣减,而严格的乐观锁要求库存值完全匹配,避免高并发下的超卖情况。

  • CAS(Compare And Swap):CAS 是一种无锁的操作,通过比较内存中的值是否是预期的值,如果是就更新,否则重试。它在并发高的场景中非常有效,避免了加锁带来的性能开销。


5. 限购策略:一人一单

在秒杀商品业务中,通常会限制每个用户只能购买一件商品。这可以通过在订单表中查询用户是否已经下单来实现。

解决方案

  • 在秒杀开始前,查询当前用户是否已经下过订单。如果下单了,直接返回失败信息,防止重复下单。

SQL 示例

SELECT COUNT(1) 
FROM orders 
WHERE user_id = #{uid} 
AND product_id = #{productId};-- 如果用户没有下过单,则创建订单
INSERT INTO orders (order_id, user_id, product_id, quantity)
VALUES (#{orderId}, #{uid}, #{productId}, 1);

通过查询订单表来确保每个用户只能购买一次该商品,有效防止恶意抢购。


总结

秒杀业务的复杂性主要体现在 高并发场景下的事务管理和并发控制。在商品秒杀场景中,针对多个关键技术点进行了深度剖析:

  1. AOP 代理对象与事务管理:确保事务通过代理对象调用,避免事务失效。
  2. 并发控制与锁机制:通过 synchronized 实现单机并发控制,在分布式环境下可以使用分布式锁。
  3. 锁包含事务:锁先于事务执行,确保线程安全和数据一致性。
  4. 乐观锁与CAS:通过库存判断或版本号机制确保库存扣减的正确性,避免超卖。
  5. 限购策略:通过查询订单表限制用户的重复购买,防止一人多单。

通过合理运用这些技术,能够设计出一个稳定、高效的秒杀系统,在应对高并发时保持系统稳定性,同时确保数据的安全性和一致性。


希望这篇文章能帮助你深入理解秒杀商品业务中的关键技术点,构建更高效稳定的系统。

这篇关于深入解析秒杀业务中的核心问题 —— 从并发控制到事务管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1148480

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

4B参数秒杀GPT-3.5:MiniCPM 3.0惊艳登场!

​ 面壁智能 在 AI 的世界里,总有那么几个时刻让人惊叹不已。面壁智能推出的 MiniCPM 3.0,这个仅有4B参数的"小钢炮",正在以惊人的实力挑战着 GPT-3.5 这个曾经的AI巨人。 MiniCPM 3.0 MiniCPM 3.0 MiniCPM 3.0 目前的主要功能有: 长上下文功能:原生支持 32k 上下文长度,性能完美。我们引入了