关于抢京东券高并发的问题?
之前在一个微信公众号上做了一个抢京东券的功能, 50 张京东券,面额 50 、 100 不等,存在一张 card 表中,四个字段, id , number , money , is_taken 。
因为之前没有这种高并发处理的经验,所以使用了一种最传统的方式来实现:
方案一:来一个人我就从数据库中取一张京东券出来给他,并将该京东券标记为已使用(即更新 is_taken 字段),并将该用户插入到 winner 表中
这个方案最终导致的悲剧是,有一张京东券被两个人领取到了。
我所理解会出现这个问题的原因是获取未被占用的京东券数据( select )和更新该条京东券数据( update )是两个独立的操作,在这两个操作之间存在时间间隔,例如 A 用户刚得到了一张 100 元的京东券,还未来得及更新, B 用户涌入查询到这张京东券未被使用,所以 B 用户也获得了这张京东券。
问题一:我这个理解是正确的吗?还是有更深入的原因?
出了这个问题后,我在网上查找关于高并发相关的资料,几乎都提到了队列和锁。就我个人了解队列可以使用 redis 或者 memcacheq(这个没用过,不熟悉),所以自己想了第二种方案。
方案二:事先将京东券 id 数据压入到 redis 的 list 中,每过来一个有效的用户,就 pop 一个 id 给他(当 pop 出来的数据为空时说明京东券已经被抢光),并将用户 id 与京东券 id 的对应关系存储到 redis 的 set 当中去,然后根据这个 id 来查找京东券数据,显示给用户京东券的面额,并将 set 中的数据存储到数据库当中去。
个人觉得这种方案会比第一种方案要好的多。但是没有真正意义上去实践过,只是个人思考的一个结果。
问题二:第二种方案是否可行?是否还有更优方案?或者说方案二是否有可以优化的地方?
问题三:在高并发时很多文章中说到的锁是一个怎样的概念呢?我的理解是这个锁就像是数据库的一个大门,一次只放一个人进去,是这样吗?具体该如何设计和使用?
问题四:在应对大流量高并发的情况时,在服务器层面要做哪些工作?
问题五:我所举得这个例子与平常类似网上商城中的秒杀功能有哪些相同和相异之处呢?是否可以按照方案二的设计思路进行设计呢?
回复内容:
之前在一个微信公众号上做了一个抢京东券的功能, 50 张京东券,面额 50 、 100 不等,存在一张 card 表中,四个字段, id , number , money , is_taken 。
因为之前没有这种高并发处理的经验,所以使用了一种最传统的方式来实现:
方案一:来一个人我就从数据库中取一张京东券出来给他,并将该京东券标记为已使用(即更新 is_taken 字段),并将该用户插入到 winner 表中
这个方案最终导致的悲剧是,有一张京东券被两个人领取到了。
我所理解会出现这个问题的原因是获取未被占用的京东券数据( select )和更新该条京东券数据( update )是两个独立的操作,在这两个操作之间存在时间间隔,例如 A 用户刚得到了一张 100 元的京东券,还未来得及更新, B 用户涌入查询到这张京东券未被使用,所以 B 用户也获得了这张京东券。
问题一:我这个理解是正确的吗?还是有更深入的原因?
出了这个问题后,我在网上查找关于高并发相关的资料,几乎都提到了队列和锁。就我个人了解队列可以使用 redis 或者 memcacheq(这个没用过,不熟悉),所以自己想了第二种方案。
方案二:事先将京东券 id 数据压入到 redis 的 list 中,每过来一个有效的用户,就 pop 一个 id 给他(当 pop 出来的数据为空时说明京东券已经被抢光),并将用户 id 与京东券 id 的对应关系存储到 redis 的 set 当中去,然后根据这个 id 来查找京东券数据,显示给用户京东券的面额,并将 set 中的数据存储到数据库当中去。
个人觉得这种方案会比第一种方案要好的多。但是没有真正意义上去实践过,只是个人思考的一个结果。
问题二:第二种方案是否可行?是否还有更优方案?或者说方案二是否有可以优化的地方?
问题三:在高并发时很多文章中说到的锁是一个怎样的概念呢?我的理解是这个锁就像是数据库的一个大门,一次只放一个人进去,是这样吗?具体该如何设计和使用?
问题四:在应对大流量高并发的情况时,在服务器层面要做哪些工作?
问题五:我所举得这个例子与平常类似网上商城中的秒杀功能有哪些相同和相异之处呢?是否可以按照方案二的设计思路进行设计呢?
我估计你的方案一是这样子的
<code>select * from card where is_token=0 limit 1; //有结果时,继续执行以下语句 update card set is_token=1 where id=xx; insert into winner ...</code>
改进
<code>select * from card where is_token=0 limit 1; //有结果时,继续执行以下语句 update card set is_token=1 where id=xx and is_token=0; //获取影响行数,为0则失败,否则执行 insert into winner ...</code>
方案二
可行。
因为你的业务逻辑比较简单,也可以使用redis的计数器
即当计数器
问题三 锁
悲观锁(Pessimistic Lock)
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
<code>begin; select * from card where is_token=0 limit 1 for update; </code>
乐观锁
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。参考改进后的方案一。
乐观锁用的比较多,使用redis的watch

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

PHP和Python各有优势,选择应基于项目需求。1.PHP适合web开发,语法简单,执行效率高。2.Python适用于数据科学和机器学习,语法简洁,库丰富。

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

PHP在电子商务、内容管理系统和API开发中广泛应用。1)电子商务:用于购物车功能和支付处理。2)内容管理系统:用于动态内容生成和用户管理。3)API开发:用于RESTfulAPI开发和API安全性。通过性能优化和最佳实践,PHP应用的效率和可维护性得以提升。

PHP仍然具有活力,其在现代编程领域中依然占据重要地位。1)PHP的简单易学和强大社区支持使其在Web开发中广泛应用;2)其灵活性和稳定性使其在处理Web表单、数据库操作和文件处理等方面表现出色;3)PHP不断进化和优化,适用于初学者和经验丰富的开发者。

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

PHP和Python各有优劣,选择取决于项目需求和个人偏好。1.PHP适合快速开发和维护大型Web应用。2.Python在数据科学和机器学习领域占据主导地位。
