2. 事务
- delete 语句的和查询的加锁方式相同
- limit 语句,遍历到满足条件的 n 条数据后,之后不再加 next-key lock
死锁:不同线程可以给同一个间隙加锁。
意思时只有我这个线程可以操控这个间隙,其他线程不能使用,加锁时不会检测是否冲突的,但是如果两个都给同一个间隙上锁,之后两个线程都没办法在这个间隙上更新数据了,都会陷入等待另一个线程的间隙锁释放,也就是
死锁。
如果使用读提交隔离级别,那么只加行锁,不加间隙锁,语句执行过程中加上的行锁,在语句执行完成后,就要把 “不满足条件的行”上的行锁直接释放了,不需要等到事务提交才释放。
2. 事务
2-1:for update的使用场景
一般这些操作都是很长一串并且是开启事务的。
如果库存刚开始读的时候是1,而立马另一个进程进行了update将库存更新为0了,而事务还没有结束,会将错的数据一直执行下去,就会有问题。
需要 for upate 进行数据加锁防止高并发时候数据出错,即使事务保持当前读状态。
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset;
# 如果只给定一个参数,表示记录数。
mysql> SELECT * FROM orange LIMIT 5;# 检索前5条记录(1-5)
相当于
mysql> SELECT * from orange LIMIT 0,5;
两个参数,第一个参数表示offset, 第二个参数为记录数。
mysql> SELECT * FROM orange LIMIT 10,15; // 检索记录11-25
如果你想要清除一些MySQL使用内部缓存,你应该使用FLUSH命令
2-2:事务隔离
innodb 支持 RC 和 RR 隔离级别实现是用的一致性视图(consistent read view)
事务在启动时会拍一个快照,这个快照是基于整个库的。
基于整个库的意思就是说一个事务内,整个库的修改对于该事务都是不可见的(对于快照读的情况)
如果在事务内 select t 表,另外的事务执行了DDL t表,根据发生时间,只有两种情况
- 报错
(2)事务在启动时,找到已提交的最大事务ID记为up_limit_id。
(3)事务在更新一条语句时
比如 id=1 改为了 id=2.会把 id=1 和该行之前的 row trx_id 写到 undo log 里, 并且在数据页上把 id 的值改为 2,并且把修改这条语句的transaction id 记在该行行头
(4)再定一个规矩
一个事务要查看一条数据时,必须先用该事务的 up_limit_id 与该行的transaction id 做比对
如果 up_limit_id >= transaction id,那么可以看如果 up_limit_id < transaction id,则只能去 undo log 里去取。
去 undo log 查找数据的时候,也需要做比对,必须 up_limit_id > transaction id,才返回数据
2-3:什么是当前读
由于当前读都是先读后写,只能读当前的值,所以为当前读会更新事务内的 up_limit_id 为该事务的 transaction
你提到了隐藏列有一个DB_ROW_ID,是干嘛的?那假设有10个update,到第九个回滚了,DB_ROLL_PTR如何做的,那提交了是否更新DB_ROLL_PTR?
为什么 rr 能实现可重复读而 rc 不能,分两种情况
(1)快照读的情况下:
rr不能更新事务内的 up_limit_id ,而 rc 每次会把 up_limit_id 更新为快照读之前最新已提交事务的 transaction id, 则 rc 不能可重复读
(2)当前读的情况下:
rr 是利用 record lock+gap lock来实现的,而 rc 没有 gap,所以 rc 不能可重复读
2-4:选择普通索引还是唯一索引?
1、对于查询过程来说:
(1)普通索引
查到满足条件的第一个记录后,继续查找下一个记录,知道第一个不满足条件的记录
(2)唯一索引
由于索引唯一性,查到第一个满足条件的记录后,停止检索
但是,两者的性能差距微乎其微。因为InnoDB根据数据页来读写的。
2、对于更新过程来说:
概念:change buffer
当需要更新一个数据页:
purge:将 change buffer 中的操作应用到原数据页上,得到最新结果的过程,成为 purge
访问这个数据页会触发 purge,系统有后台线程定期 purge,在数据库正常关闭的过程中,也会执行 purge
唯一索引的更新不能使用 change buffer
change buffer 用的是 buffer pool 里的内存,change buffer 的大小,可以通过参数 innodb_change_buffer_max_size 来动态设置。这个参数设置为50的时候,表示 change buffer 的大小最多只能
占用 buffer pool 的50%。
将数据从磁盘读入内存涉及随机IO的访问,是数据库里面成本最高的操作之一。
change buffer 因为减少了随机磁盘访问,所以对更新性能的提升很明显。
change buffer使用场景:
在一个数据页做purge之前,change buffer记录的变更越多,收益就越大。
对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时change buffer的使用效果最好。这种业务模型常见的就是账单类、日志类的系统。
反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在change buffer,但之后由于马上要访问这个数据页,会立即触发purge过程。
这样随机访问IO的次数不会减少,反而增加了change buffer的维护代价。所以,对于这种业务模式来说,change buffer反而起到了副作用。
索引的选择和实践:
尽可能使用普通索引。
redo log主要节省的是随机写磁盘的IO消耗(转成顺序写),而change buffer主要节省的则是随机读磁盘的IO消耗。
2-5:char 和 varchar 的区别?
char 是固定长度类型,比如:定义 char(10),当你输入”abc”三个字符的时候,它们占的空间还是 10 个字节,其他 7 个是空字节。varchar 长度可变
存储情况不同
以 compact 行格式为例:
一条完整的记录由两部分组成
- 变长字段的真正数据内容
- 该变长字段所占用的字节数
该变长字段所占用的字节数被放在变长字段列表中,并且按照列的顺序逆序存放。
而 char 类型的数据则只需要存储其真正的数据内容。
对于类型为 char(M) 的列
全站分卷索引 · 230 卷
- 1代码随想录知识星球精华(最强八股文)第五版(计算机基础篇)
- 2DNS
- 3DNS解析过程
- 4递归查询和迭代查询
- 5HTTP特性与简述
- 6HTTP版本演变
- 7HTTP/2
- 8HTTP1.1协议的性能问题
- 9兼容HTTP1.1
- 10二进制帧
- 11并发传输
- 12服务器主动推送资源
- 13总结
- 14HTTP/3
- 15HTTP/2的缺点
- 16QUIC协议的特点
- 17HTTP/3协议
- 18HTTP缓存
- 19协商缓存
- 20HTTPS
- 21HTTPS的特点
- 22非对称加密
- 23摘要算法+数字签名
- 24数字证书
- 25证书信任链
- 26HTTPS是怎么建立连接的
- 27TCP与UDP头部格式
- 28TCP
- 29列举TCP选项
- 30TCP三次握手
- 31为什么需要三次握手?
- 32什么是半连接队列
- 33什么是SYN攻击
- 34为什么挥手需要四次
- 35TIME_WAIT 过多有什么危害?
- 36TCP的滑动窗口
- 374. 程序是如何表示发送方的四个部分的呢?
- 386. 接收窗口和发送窗口的大小是相等的吗?
- 391. 慢启动
- 403. 拥塞发生
- 414. 快速恢复
- 42IP基础
- 43IP地址
- 44在浏览器中输入URL并按下回车之后会发生什么
- 45TCP 抓包实践
- 46TCP连接与断开优化
- 47TCP内核参数
- 48主动方的优化
- 49被动方的优化
- 50Linux是如何收发网络包的
- 51收发流程
- 52面试题
- 53TCP/IP四层网络模型
- 54五层网络体系结构
- 55HTTP响应报文
- 56HTTP常见字段
- 57什么是TCP粘包问题?如何解决TCP粘包问题?
- 58UDP会不会产生粘包问题呢?
- 59请求报文
- 60时间消耗
- 61HTTP缓存有几种
- 62HTTP1.0和HTTP1.1的区别?
- 63HTPP1.1和HTTP1.0有什么区别
- 64HTTP/3
- 65HTTPS是如何建立连接的
- 66DNS是什么
- 67递归查询和迭代查询
- 68TCP与UDP的区别
- 69TCP和UDP分别在什么场景使用?
- 70三次握手的过程
- 71Keep-Alive的优缺点
- 72CDN的工作流程
- 73Session的工作原理
- 74TCP重传机制是怎么实现的?
- 75什么是SS0
- 76HTTP优化方案
- 77浏览器地址栏输入URL回车后涉及到的流程
- 781.5 浏览器发送HTTP/HTTPS请求到web服务器
- 79SYN攻击
- 80操作系统
- 81操作系统的功能
- 82进程和线程
- 83线程基础
- 84进程调度
- 85进程调度方式
- 86进程通信
- 87消息传递(消息队列)
- 88信号量
- 89信号
- 90线程通信
- 91多线程
- 92进程通信
- 93消息队列
- 94信号
- 95守护进程
- 96互斥与同步
- 974. 互斥锁解锁
- 983. 处理方法
- 99读写锁
- 1002. 销毁读写锁
- 1014. 写锁定
- 1021. 创建条件变量
- 1034. 阻塞线程
- 104信号量
- 1054. V操作
- 1062. 读者-写者问题
- 107存储系统
- 108虚拟内存
- 109内存分段
- 110内存分页
- 111虚拟内存
- 112文件系统
- 1135. 文件访问
- 114目录
- 1154. 目录操作
- 1163. 目录的实现
- 1177. 虚拟文件系统
- 1184. 文件系统性能
- 119磁盘编址
- 120三层抽象
- 121外设管理
- 122Linux
- 123select/poll/epoll的区别和联系
- 124Linux 内存管理
- 125Linux虚拟内存
- 126Linux 信号
- 127Linux设计
- 1283. 各种IO模型的比较
- 129Linux网络
- 130Linux中的软链接和硬链接有什么区别?
- 131什么是中断和异常
- 132信号和信号量有什么区别
- 133Linux中如何查看一个进程
- 134进程、线程的区别?
- 135进程之间的通信方式
- 136如何解除死锁
- 137分段和分页的区别
- 138IO多路复用
- 139MySQL表连接
- 140过滤条件
- 141执行一次update语句,发生了什么
- 142用户账号存储
- 143用户账号删除
- 144索引
- 145索引有哪些类别
- 1462. 按照存储分类
- 1475. 按照字段个数分类
- 148索引区分度
- 149索引什么时候会失效
- 150事务的四大特性ACID
- 151并行事务会出现什么问题
- 152幻读是如何解决的
- 153事务隔离的实现
- 154读已提交是怎么实现的
- 155锁
- 1561、全局锁
- 1573、行级锁
- 158锁的划分
- 1592.、程序员角度
- 160Innodb使用表锁还是行锁
- 161什么是binlog
- 162执行引擎
- 163MySQL常见问题
- 1642. 事务
- 1653. 脏页
- 1664. 表结构
- 1676. 查询效率
- 168MySQL分库分表
- 169垂直分表
- 170水平分库
- 171分库分表的问题
- 172数据库排序思路
- 173MySQL主从复制
- 1745. 主从复制模式
- 175面试题
- 176执行一条select语句,发生了什么?
- 177你对关系范式有哪些了解
- 178数据库
- 179Redis基础
- 180Redis单线程为什么还这么快
- 181Redis底层数据结构
- 182Redis持久化
- 183AOF日志
- 184RDB快照
- 185Redis功能
- 1862. 哨兵模式
- 1873. 切片集群
- 188Redis哨兵机制是什么
- 189什么是集群脑裂
- 190过期删除策略有哪些
- 191Redis的LRU算法和LFU算法有什么区别
- 192什么是缓存击穿
- 193如何保证删除缓存操作一定能成功?
- 194为什么Redis是单线程
- 195Redis底层使用了什么数据结构
- 196Redis实现分布式锁
- 197缓存中的热点数据和冷数据是什么
- 198缓存雪崩、击穿、穿透和解决办法【常问】
- 199Redis过期删除策略有哪些
- 200关键概念
- 201单例模式的应用场景
- 202工厂模式
- 203实际应用
- 204抽象工厂模式
- 205概念
- 206应用
- 207实现步骤
- 208主要角色
- 209代理模式应用
- 210策略模式
- 211示例
- 212装饰模式
- 213主要角色
- 21423种设计模式的概念
- 215创建型模式
- 216行为型模式
- 217设计原则
- 218迪米特法则
- 219你在实际开发中用过哪些设计模式
- 220依赖倒置
- 221代理模式和适配器模式有什么区别
- 222固定长度编码
- 223冯诺依曼模型
- 224总线
- 225输入/输出设备
- 226编译系统如何工作
- 227处理器解释指令
- 228场景题 & 系统设计
- 229如何设计一个本地缓存
- 230如何设计一个RPC框架