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

redis秒杀

redis优惠券秒杀

为什么订单表订单ID不采用自增长?

  • id规律性太明显,容易被用户猜测到(比如第一天下订单id10,第二天下订单id100,在昨天的1天内只卖出90商品)
  • 受单表数据量限制(订单数据量大,日积月累单张表就存不下去这么多数据记录)如果单张表存不了,我们使用多张表的话,表独立的,自增长的话id会出现重复,到时用户买到的商品有问题售后就麻烦了

这时我们就要使用全局ID生成器,是一种在分布式系统下生成全局唯一ID的工具,满足以下特点:唯一性、高可用、高性能、递增性、安全性

为了增加id的安全性,我们可以直接不使用redis自增的数值,而是拼接一些其他的信息 

定义一个类RedisIdWorker类并且配置@Component由spring管理的bean

package com.hmdp.utils;import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;@Component
public class RedisIdWorker {@Resourceprivate StringRedisTemplate stringRedisTemplate;private static final long BEGIN_TIMESTAMP=1672531200;private static final int COUNT_BIT=32;public long nextId(String keyPrefix){// 1.生成时间戳LocalDateTime now = LocalDateTime.now();long nowSecond = now.toEpochSecond(ZoneOffset.UTC);long timestamp=nowSecond-BEGIN_TIMESTAMP;//当前时间戳// 2.生成序列号// 获取当前日期String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));// 自增长// 需要加上日期 因为自增上限是2^64,日积月累的销量越来越多,出32位容易,未来就存不下去,不能使用同一个keyLong count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);// 3.拼接并返回// 我们以为时间戳在最低位 要让他处于高位必须移位 移多少位得看给序列化号足够的位置(这里是32位)return timestamp<<COUNT_BIT|count;}/*public static void main(String[] args) {LocalDateTime time = LocalDateTime.of(2023, 1, 1, 0, 0, 0);long second = time.toEpochSecond(ZoneOffset.UTC);System.out.println(second);//1672531200}*/
}

需要加上日期,不然整个业务订单一直采用同一个key自增长,时隔几年,订单越来越多,redis单个key的值自增上限是2的64次方(好处就是每天业务订单量都是不同的key,一天的订单量不会超过2^32)

package com.hmdp;import com.hmdp.entity.Shop;
import com.hmdp.service.impl.ShopServiceImpl;
import com.hmdp.utils.CacheClient;
import com.hmdp.utils.RedisIdWorker;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;import static com.hmdp.utils.RedisConstants.CACHE_SHOP_KEY;@SpringBootTest
class HmDianPingApplicationTests {@Resourceprivate CacheClient cacheClient;@Resourceprivate ShopServiceImpl shopService;@Resourceprivate RedisIdWorker redisIdWorker;private ExecutorService es = Executors.newFixedThreadPool(500);@Testpublic void testIdWorker() throws InterruptedException {CountDownLatch latch = new CountDownLatch(300);Runnable task = () -> {for (int i = 0; i < 100; i++) {long id = redisIdWorker.nextId("order");System.out.println("id=" + id);}latch.countDown();};long begin = System.currentTimeMillis();for (int i = 0; i < 300; i++) {es.submit(task);//线程池异步所以使用CountDownLatch}latch.await();//等待所有countDown结束long end = System.currentTimeMillis();System.out.println("time=" + (end - begin));}@Testvoid testSaveShop() throws InterruptedException {//shopService.saveShop2Redis(1L,10L);Shop shop = shopService.getById(1L);cacheClient.setWithLogicalExpire(CACHE_SHOP_KEY + 1L, shop, 10L, TimeUnit.SECONDS);}
}

 

添加秒杀劵(这里我们没有编写后台管理系统,为了方便起见,使用postman测试)

{"shopId": 1,"title": "100元代金券","subTitle": "周一到周五均可使用","rules": "全场通用\\n无需预约\\n可无限叠加\\不兑现、不找零\\n仅限堂食","payValue": 8000,"actualValue": 10000,"type": 1,"stock": 100,"beginTime":"2023-02-23T19:00:00","endTime":"2023-02-23T20:00:00"
}

注意,我们点击发送请求前需要添加请求头信息 控制台打印其值即token,否则会报401错

 添加成功

优惠券秒杀下单功能 

package com.hmdp.service.impl;import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.time.LocalDateTime;/*** <p>*  服务实现类* </p>** @author 虎哥* @since 2021-12-22*/
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService seckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Override@Transactionalpublic Result seckillVoucher(Long voucherId) {// 1.查询优惠券SeckillVoucher voucher = seckillVoucherService.getById(voucherId);// 2.判断秒杀是否开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {// 尚未开始return Result.fail("秒杀尚未开始!");}// 3.判断秒杀是否结束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {return Result.fail("秒杀已经结束!");}// 4.判断库存是否充足if (voucher.getStock()<1) {// 库存不足return Result.fail("库存不足!");}// 5.扣减库存// eq代表where条件boolean success=seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id",voucherId).update();if (!success){// 扣减失败return Result.fail("库存不足!");}// 6.创建订单VoucherOrder voucherOrder = new VoucherOrder();// 6.1. 订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 6.2. 用户idLong userId = UserHolder.getUser().getId();voucherOrder.setUserId(userId);// 6.3. 代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 7.返回订单Idreturn Result.ok(orderId);}
}

超卖

版本号法+CAS法(compare and set) 

// 5.扣减库存// eq代表where条件boolean success=seckillVoucherService.update().setSql("stock=stock-1")// set stock=stock-1.eq("voucher_id",voucherId).eq("stock",voucher.getStock())// where id=? and stock=?.update();

乐观锁成功率太低(因为只要库存不一致就失败)优化:就是库存大于0即可

乐观锁的方案是在更新数据时候去使用的

// 5.扣减库存// eq代表where条件boolean success=seckillVoucherService.update().setSql("stock=stock-1")// set stock=stock-1.eq("voucher_id",voucherId).gt("stock",0)// where id=? and stock>0.update();

一人一单(知识点:动态代理、事务、aop、悲观锁、锁的范围)

这里是新增数据,无法判断是否有无修改过,因为它不存在,判断是否存在,只能用悲观锁方案解决(从查询订单到判断订单到新增订单这一段逻辑加上悲观锁)

虽然userId值一样,但是每次调用toString方法都是新的对象 

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency>

暴露代理对象 

package com.hmdp;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan("com.hmdp.mapper")
@SpringBootApplication
public class HmDianPingApplication {public static void main(String[] args) {SpringApplication.run(HmDianPingApplication.class, args);}}

之前在方法内部添加锁可能会发生情况:开启事务执行,获取锁查询完减库存提交订单释放锁才会提交事务,函数执行完之后由spring去提交事务,锁释放意味着其他线程也可以进来了,而此时事务尚未提交,其他线程趁此时进来,去查询订单的话,刚刚新增的订单很有可能还未写进数据库,因为还未提交,查询依然不存在,产生并发问题, 可知我们刚才锁定的范围缩小了,解决方案:把整个函数锁起来,先事务提交再释放锁,那我们就要把锁放在函数外面,这时就出现事务问题消失 因为此时调用方法的直接是当前目标对象IVoucherOrderService对象,没有事务功能,事务要想生效,其实是我们spring对当前这个类进行动态代理, 拿到当前类的代理对象,用它来作事务处理 

package com.hmdp.service.impl;import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.time.LocalDateTime;/*** <p>*  服务实现类* </p>** @author 虎哥* @since 2021-12-22*/
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {@Resourceprivate ISeckillVoucherService seckillVoucherService;@Resourceprivate RedisIdWorker redisIdWorker;@Overridepublic Result seckillVoucher(Long voucherId) {// 1.查询优惠券SeckillVoucher voucher = seckillVoucherService.getById(voucherId);// 2.判断秒杀是否开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {// 尚未开始return Result.fail("秒杀尚未开始!");}// 3.判断秒杀是否结束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {return Result.fail("秒杀已经结束!");}// 4.判断库存是否充足if (voucher.getStock()<1) {// 库存不足return Result.fail("库存不足!");}// 5.一人一单Long userId = UserHolder.getUser().getId();synchronized (userId.toString().intern()) {// 获取代理对象(事务)IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}}// 方法加上同步锁肯定是线程安全的 this指向IVoucherOrderService// 不建议加上方法上 因为代表任何用户来了都要加上锁 串行执行 性能低// 我们只需要同一用户进来才需要加锁@Transactionalpublic Result createVoucherOrder(Long voucherId){// 5.一人一单Long userId = UserHolder.getUser().getId();// 当用户id值一样时,锁就一样// synchronized (userId.toString().intern()) {// 5.1.查询订单int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();// 5.2.判断是否存在if (count > 0) {//用户已经购买过return Result.fail("用户已经购买过一次!");}// 6.扣减库存// eq代表where条件boolean success = seckillVoucherService.update().setSql("stock=stock-1")// set stock=stock-1.eq("voucher_id", voucherId).gt("stock", 0)// where id=? and stock>0.update();if (!success) {// 扣减失败return Result.fail("库存不足!");}// 7.创建订单VoucherOrder voucherOrder = new VoucherOrder();// 7.1. 订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 7.2. 用户idvoucherOrder.setUserId(userId);// 7.3. 代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 8.返回订单Idreturn Result.ok(orderId);//}}
}

上述处理方案虽然解决了一人一单的并发安全问题(通过加锁可以解决单机情况下的问题),但是在集群模式下就不行了 

通过加锁可以解决在单机情况下的一人一单安全问题,但是在集群模式下就不行了(每个jvm都有自己的锁监视器,集群模式下各个服务器的锁不共享)。
因此,我们的解决方案就是实现一个共享的锁监视器,即:
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 

 

相关文章:

redis秒杀

redis优惠券秒杀 为什么订单表订单ID不采用自增长&#xff1f; id规律性太明显&#xff0c;容易被用户猜测到&#xff08;比如第一天下订单id10&#xff0c;第二天下订单id100&#xff0c;在昨天的1天内只卖出90商品&#xff09;受单表数据量限制&#xff08;订单数据量大&am…...

JS学习第3天——Web APIs之DOM(什么是DOM,相关API【创建、增删改查、属性操作、事件操作API】)

目录一、Web APIs介绍1、API2、Web API二、DOM1、DOM树2、获取元素3、事件基础4、操作元素属性5、节点&#xff08;node&#xff09;操作三、DOM操作总结&#xff08;创建、增删改查、属性操作、事件操作API&#xff09;1、创建2、增3、删4、改5、查6、属性操作7、事件操作四、…...

【MySQL】增删改操作(基础篇)

目录 1、新增操作(Create) 1.1 单行数据 全列插入 1.2 多行数据 全列插入 1.3 单行数据 指定列插入 2、修改操作(Update) 3、删除操作(Delete) 1、新增操作(Create) 如何给一张表新增数据呢&#xff1f; 新增(Create)&#xff0c;在我们数据库中&#xff0c;用 ins…...

STM32—DMA

什么是DMA&#xff1f; DMA(Direct Memory Access&#xff0c;直接存储器访问) 提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通&#xff0c;而不需要依赖于CPU&#xff0c;在这个时间中&#xff0c;CPU对于内存的工作来…...

C语言刷题(3)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容还是做几道题噢&#xff0c;好好复习一下之前的知识点&#xff0c;现在&#xff0c;就让我们开始复习吧 牛客网在线编程_编程学习|练习题_数据结构|系统设计题库 倒置字符串_牛客题霸_牛客网 BC40 竞选社长 BC41 你是天才…...

搭建Vue工程

搭建Vue工程 localhost 127.0.0.1 域名 IP 192.168.0.28 联网IP 最后都会渲染到一个页面里面&#xff0c;有多少个页面就有多少个页面模板。 vue里面改webpack配置 vue.config.js 配置参考 | Vue CLI /assets /api* 开发的时候用到的请求后台地址 和 项目真实部署上线的时候 请…...

C语言汉诺塔问题【图文详解】

汉诺塔1. 什么是汉诺塔2. 有关汉诺塔的有趣故事3. 利用动画来演示汉诺塔4. 如何用C语言实现汉诺塔1. 什么是汉诺塔 源于印度古老传说的益智玩具 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造…...

1、RocketMQ概述

文章目录1 MQ概述1.1 MQ简介1.2 MQ用途1.3 常见MQ产品1.4 MQ常见协议2 RocketMQ概述2.1 RocketMQ简介2.2 RocketMQ发展历程尚硅谷RocketMQ教程-讲师&#xff1a;Reythor雷&#xff08;老雷&#xff09; 我们缺乏的不是知识&#xff0c;而是学而不厌的态度 1 MQ概述 1.1 MQ简介…...

【POJ 3352】Road Construction 题解(Tarjan算法求边双连通分量缩点)

描述 现在几乎是夏天&#xff0c;这意味着几乎是夏天的施工时间&#xff01;今年&#xff0c;负责偏远岛热带岛屿天堂道路的好心人希望修复和升级岛上各个旅游景点之间的各种道路。 道路本身也很有趣。由于岛上的奇怪风俗&#xff0c;道路的安排使得它们不会在交叉路口相遇&…...

Python—单分支结构

&#xff08;1&#xff09;if分支语句 Python中if语句的语法结构&#xff1a; if <条件表达式>&#xff1a;    满足条件运行的代码1    满足条件运行的代码2 代码示例&#xff1a; age 12 if age > 18:print(去上网)if 1 1 2 and :print(我满足条件了)if 1 …...

rabbitmq添加用户,虚拟机步,设置rabbitmq配置文件

第一步&#xff0c;登录后台控制页面 http://ip:15672第二步&#xff0c;添加用户和权限 重点&#xff1a;选择Admin和Users 第三步&#xff0c;添加虚拟机 点击侧边的Virtual Hosts 第四步将虚拟机和用户搭配 注意新建好后&#xff0c;在虚拟机列表中&#xff0c;点击虚拟机…...

Codeforces Round#853 div2 A-C

Codeforces Round#853 div2 A-C 等了很久终于迎来了一场cf比赛&#xff0c;白天出去玩了一圈&#xff0c;晚上回来打比赛&#xff0c;这次只出了A,B题。C题思路很巧妙&#xff0c;赛时没做出来&#xff0c;看了大佬学习到了&#xff0c;还是很不错。 A.Serval and Mocha’s A…...

软考之操作系统知识

目录 1.进程管理-进程的概念 2.进程的三态图和五态图 3.进程的同步与互斥 4.PV操作应用 5.死锁问题 6.银行家算法 7.存储管理 8.段式存储组织 9.段页式存储组织 10.页面置换算法 11.磁盘管理 12.作业管理 13.索引文件结构 14.树型目录结构 15.空闲存储空间管理 …...

【线性代数/计算复杂性理论】积和式的指数时间算法:Ryser算法

文章目录一、积和式的定义二、Ryser算法三、代码实现一、积和式的定义 积和式&#xff08;permanent&#xff09;是一种和行列式长得很像的矩阵函数。在介绍积和式之前&#xff0c;我们先看看行列式&#xff08;determinant&#xff09;的定义。 首先需要引入“排列”&#x…...

代码随想录 NO52 | 动态规划_leetcode 647. 回文子串 516.最长回文子序列

动态规划_leetcode 647. 回文子串 516.最长回文子序列今天是动态规划最后一天的题了&#xff0c;整个过程已经接近尾声了&#xff01; 647. 回文子串 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 本题如果我们定义&#xff0c;dp[i] 为 下标i结尾的字符串有 dp…...

【数据挖掘】1、综述:背景、数据的特征、数据挖掘的六大应用方向、有趣的案例

目录一、背景1.1 学习资料1.2 数据的特征1.3 数据挖掘的应用案例1.4 获取数据集1.5 数据挖掘的定义二、分类三、聚类四、关联分析五、回归六、可视化七、数据预处理八、有趣的案例8.1 隐私保护8.2 云计算的弹性资源8.3 并行计算九、总结一、背景 1.1 学习资料 推荐书籍如下&a…...

【架构师】零基础到精通——康威定律

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名Coder&#xff0c;软件设计师/鸿蒙高级工程师认证&#xff0c;在备战高级架构师/系统分析师&#xff0c;欢迎关注小弟&#xff01; 博主小留言…...

Could not extract response: no suitable HttpMessageConverter

版本&#xff1a;spring-cloud-openfeign-core-2.1.1.RELEASE.jar&#xff0c;spring-webmvc-5.1.14.RELEASE.jar&#xff0c;jetty-server-9.4.41.v20210516.jar&#xff0c;tomcat-embed-core-9.0.48.jar 问题背景 生产服务请求下游服务时偶发抛出下面的异常&#xff0c;下…...

文献计量三大定律之一---洛特卡定律及普赖斯定律

科学生产率是洛特卡定律的基础&#xff0c;科学生产率”(Scientific Productivity)&#xff09;是指科学家&#xff08;科研人员&#xff09;在科学上所表现出的能力和工作效率&#xff0c;通常用其生产的科学文献的数量来衡量。 1926年&#xff0c;洛特卡在一篇论文中提出了科…...

2023年软考高级网络规划设计师

网络规划设计师是软考高级考试科目之一&#xff0c;也是比较难的科目&#xff0c;据官方数据统计网规每年的通过率很低&#xff0c;而且每年只有下半年11月份考一次&#xff0c;如果是直接裸考&#xff0c;估计很悬哦~ 但是你参加考试获得证书的过程就是一个学习网络规划系统知…...

数据治理驱动因素 -报考题

数据治理并不是到此为止&#xff0c;而是需要直接与企业战略保持一致。数据治理越显著地帮助解决组织问题&#xff0c;人们越有可能改变行为、接受数据治理实践。数据治理的驱动因素大多聚焦于减少风险或者改进流程。&#xff08;1&#xff09;减少风险1&#xff09;一般性风险…...

2023淘宝天猫38节红包满减优惠活动时间是从几月几号什么时候开始?

2023年淘宝天猫38节活动将于2023年3月2日中午12点正式开始&#xff0c;活动将持续至2023年3月8日晚上23点59分。届时&#xff0c;淘宝天猫将推出一系列的优惠活动和红包福利&#xff0c;为广大女性用户送上节日的祝福和福利。在这个特别的节日里&#xff0c;淘宝天猫为女性用户…...

Hive表优化、表设计优化、Hive表数据优化(ORC)、数据压缩、存储优化

文章目录Hive表优化Hive表设计优化分区表结构 - 分区设计思想分桶表结构 - Join问题Hive中的索引Hive表数据优化常见文件格式TextFileSequenceFileParquetORC数据压缩存储优化 - 避免小文件生成存储优化 - 合并输入的小文件存储优化 - ORC文件索引Row Group IndexBloom Filter …...

LearnOpenGL-入门-着色器

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject LearnOpenGL中文官网&#xff1a;https://learnopengl-cn.github.io/ 文章目录着色器GLSL数据类型输入与输…...

【谷粒学院】vue、axios、element-ui、node.js(44~58)

44.前端技术-vue入门 &#x1f9e8;Vue.js 是什么 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。 Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。另一方面&#xff0c;当与现代化的工具…...

【一些回忆】2022.02.26-2023.02.26 一个普通男孩的365天

&#x1f483;&#x1f3fc; 本人简介&#xff1a;男 &#x1f476;&#x1f3fc; 年龄&#xff1a;18 &#x1f91e; 作者&#xff1a;那就叫我亮亮叭 &#x1f4d5; 专栏&#xff1a;一些回忆 为什么选择在这个时间节点回忆一下呢&#xff1f; 一是因为今天距离2023高考仅剩1…...

OSPF的多区域特性 (电子科技大学TCP/IP实验三)

一&#xff0e;实验目的 1、掌握OSPF 协议中区域的类型、特征和作用 2、掌握OSPF 路由器的类型、特征和作用 3、掌握OSPF LSA 分组的类型、特征和作用 4、理解OSPF 区域类型、路由器类型和OSPF LSA 分组类型间的相互关系 二&#xff0e;预备知识 1、静态路由选择和动态路…...

(四十四)多个事务更新同一行数据时,是如何加锁避免脏写的?

之前我们已经用很多篇幅给大家讲解了多个事务并发运行的时候&#xff0c;如果同时要读写一批数据&#xff0c;此时读和写时间的关系是如何协调的&#xff0c;毕竟要是你不协调好的话&#xff0c;可能就会有脏读、不可重复读、幻读等一系列的问题。 简单来说&#xff0c;脏读、…...

【数据库】第十二章 数据库管理

第12章 数据库管理 数据库的物理存储 关于内存、外存、磁盘、硬盘、软盘、光盘的区别_Allenzyg的博客-CSDN博客_磁盘和硬盘的区别 数据库记录在磁盘上的存储 定长&#xff0c;变长跨块&#xff0c;非跨快 文件的组织方方法&#xff1a; 无序记录文件(堆文件heap或pile file…...

Redis源码---整体架构

目录 前言 Redis目录结构 前言 deps目录 src 目录 tests 目录 utils 目录 重要的配置文件 Redis 功能模块与源码对应 前言 服务器实例 数据库数据类型与操作 高可靠性和高可扩展性 辅助功能 前言 以先面后点的方法推进无特殊说明&#xff0c;都是基于 Redis 5.0.…...