基于o2o的旅游网站建设,asp网站目录权限,做电子手环网站需求分析,小视频网站开发Redis实现购物秒杀及分布式锁
全局唯一ID
Redis自增ID策略
ID构造是:时间戳 + 计数器 每天一个key,方便统计订单量
业务实现
获取指定时间的秒数
LocalDateTime timeBegin = LocalDateTime.of(2024, 1, 1, 0, 0, 0);
long second = timeBegin.toEpochSecond(ZoneOffset…Redis实现购物秒杀及分布式锁
全局唯一ID
Redis自增ID策略
ID构造是:时间戳 + 计数器 每天一个key,方便统计订单量
业务实现
获取指定时间的秒数
LocalDateTime timeBegin = LocalDateTime.of(2024, 1, 1, 0, 0, 0);
long second = timeBegin.toEpochSecond(ZoneOffset.UTC);获取当前时间的秒数
long now = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);全局唯一ID业务代码
public Long getID(String key) {// 获取时间戳long now = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);long timestamp = now - TIMESTAMP_BEGIN;// 利用redis实现自增长String date = new SimpleDateFormat("yyyyMMdd").format(new Date());Long inc = redisTemplate.opsForValue().increment("ID:" + key + ":" + date);// 拼接并返回return timestamp 32 | inc;
}实现秒杀下单
秒杀下单逻辑流程 业务实现 #mermaid-svg-jdMXZew0FXz7VC4U {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jdMXZew0FXz7VC4U .error-icon{fill:#552222;}#mermaid-svg-jdMXZew0FXz7VC4U .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jdMXZew0FXz7VC4U .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-jdMXZew0FXz7VC4U .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jdMXZew0FXz7VC4U .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jdMXZew0FXz7VC4U .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jdMXZew0FXz7VC4U .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jdMXZew0FXz7VC4U .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jdMXZew0FXz7VC4U .marker.cross{stroke:#333333;}#mermaid-svg-jdMXZew0FXz7VC4U svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jdMXZew0FXz7VC4U .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jdMXZew0FXz7VC4U .cluster-label text{fill:#333;}#mermaid-svg-jdMXZew0FXz7VC4U .cluster-label span{color:#333;}#mermaid-svg-jdMXZew0FXz7VC4U .label text,#mermaid-svg-jdMXZew0FXz7VC4U span{fill:#333;color:#333;}#mermaid-svg-jdMXZew0FXz7VC4U .node rect,#mermaid-svg-jdMXZew0FXz7VC4U .node circle,#mermaid-svg-jdMXZew0FXz7VC4U .node ellipse,#mermaid-svg-jdMXZew0FXz7VC4U .node polygon,#mermaid-svg-jdMXZew0FXz7VC4U .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jdMXZew0FXz7VC4U .node .label{text-align:center;}#mermaid-svg-jdMXZew0FXz7VC4U .node.clickable{cursor:pointer;}#mermaid-svg-jdMXZew0FXz7VC4U .arrowheadPath{fill:#333333;}#mermaid-svg-jdMXZew0FXz7VC4U .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jdMXZew0FXz7VC4U .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jdMXZew0FXz7VC4U .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-jdMXZew0FXz7VC4U .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-jdMXZew0FXz7VC4U .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jdMXZew0FXz7VC4U .cluster text{fill:#333;}#mermaid-svg-jdMXZew0FXz7VC4U .cluster span{color:#333;}#mermaid-svg-jdMXZew0FXz7VC4U div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jdMXZew0FXz7VC4U :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 存在 不存在 充足 不足 begin 判断库存 判断存在 end 提交商品id 返回异常 扣减库存 创建订单 返回订单id @Transactional
public String getProduct(Long id) {// 判断商品是否存在Product pro = getById(id);if (pro == null) {throw new BusinessException(400, "商品不存在");}// 判断库存int num = pro.getNum();if (num = 0) {throw new BusinessException(400, "库存不足");}// 库存 - 1pro.setNum(num - 1);update(pro, new QueryWrapper());// 下订单Ordertable order = new Ordertable();order.setOrderID(idUtil.getID("order").toString());order.setUserID(123);ordertableService.save(order);return order.getOrderID();
}“超卖”问题
问题复现
在多线程并发会产生问题
使用5000个线程进行测试 20个库存卖了210个订单 原因分析 锁的类型
超卖问题是典型的多线程安全问题,针对这一问题的常见解决方案就是加锁
悲观锁:认为线程安全问题一定会发生,因此在操作数据之前先获取锁,确保线程串行执行。
例如Synchronized、Lock都属于悲观锁乐观锁:认为线程安全问题不一定会发生,因此不加锁,只是在更新数据时去判断有没有其它线程对数据做了修改。
如果没有修改则认为是安全的,自己才更新数据。如果已经被其它线程修改说明发生了安全问题,此时可以重试或异常。乐观锁
乐观锁的关键是判断之前查询得到的数据是否有被修改过。(CAS法) 代码实现 #mermaid-svg-WlaW16mm60nQypbb {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-WlaW16mm60nQypbb .error-icon{fill:#552222;}#mermaid-svg-WlaW16mm60nQypbb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WlaW16mm60nQypbb .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-WlaW16mm60nQypbb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WlaW16mm60nQypbb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WlaW16mm60nQypbb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WlaW16mm60nQypbb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WlaW16mm60nQypbb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WlaW16mm60nQypbb .marker.cross{stroke:#333333;}#mermaid-svg-WlaW16mm60nQypbb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WlaW16mm60nQypbb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WlaW16mm60nQypbb .cluster-label text{fill:#333;}#mermaid-svg-WlaW16mm60nQypbb .cluster-label span{color:#333;}#mermaid-svg-WlaW16mm60nQypbb .label text,#mermaid-svg-WlaW16mm60nQypbb span{fill:#333;color:#333;}#mermaid-svg-WlaW16mm60nQypbb .node rect,#mermaid-svg-WlaW16mm60nQypbb .node circle,#mermaid-svg-WlaW16mm60nQypbb .node ellipse,#mermaid-svg-WlaW16mm60nQypbb .node polygon,#mermaid-svg-WlaW16mm60nQypbb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WlaW16mm60nQypbb .node .label{text-align:center;}#mermaid-svg-WlaW16mm60nQypbb .node.clickable{cursor:pointer;}#mermaid-svg-WlaW16mm60nQypbb .arrowheadPath{fill:#333333;}#mermaid-svg-WlaW16mm60nQypbb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WlaW16mm60nQypbb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WlaW16mm60nQypbb .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-WlaW16mm60nQypbb .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-WlaW16mm60nQypbb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WlaW16mm60nQypbb .cluster text{fill:#333;}#mermaid-svg-WlaW16mm60nQypbb .cluster span{color:#333;}#mermaid-svg-WlaW16mm60nQypbb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WlaW16mm60nQypbb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}