并发控制要解决什么问题?
当多个事务同时操作数据库时,如果不加控制,会出现以下四种问题:
怎么解决?两大门派
门派一:锁机制(悲观锁派)
理念:“先锁门,再办事”,怕冲突。
怎么锁:
读锁(共享锁):我读时,别人能读不能改。
写锁(排他锁):我改时,谁也别动。
锁的规矩(协议):
一级:改前加写锁 → 防丢更新。
二级:改前加写锁,读前加读锁(读完就放) → 防丢更新+脏读。
三级:改前加写锁,读前加读锁(直到事完才放) → 防丢更新+脏读+不可重复读。
门派二:MVCC(乐观锁派)
理念:“各写各的版本,最后看谁的对”,不怕冲突。
怎么玩:每条数据存多个版本,你读你的旧版本,我写我的新版本,互不阻塞。
好处:读特快,读写不打架。
代价:可能白写(提交时发现冲突,得回滚)。
你该用哪个?(怎么选)
选锁(悲观):当 写很多、抢很凶 的时候(如秒杀、库存扣减)。
选MVCC(乐观):当 读很多、写很少 的时候(如新闻网站、查询系统)。
现代数据库(如MySQL):两个混着用,MVCC为主,锁为辅。
终极心法:
默认就用数据库的默认设置(通常是“读已提交”或“可重复读”),它已经平衡得很好了。
真的遇到具体乱子(比如库存超卖),再对症下药:
防覆盖 → 用写锁(SELECT ... FOR UPDATE)或乐观锁(加版本号)。
要绝对一致 → 升隔离级别到串行化(性能会降)。
记住:并发控制就是在 “不打架” 和 “快点干” 之间找平衡。没有完美方案,只有适合场景的方案。
并行数据库体系结构
把数据库任务分给多个处理器一起干,看这些处理器怎么共享硬件。
四种架构:从“亲密”到“独立”
想象一个办公室,看工位、文件柜怎么分配:
- 共享内存(最亲密)
场景:一个开放办公室,所有人用同一个大桌子(内存)和同一个文件柜(磁盘),靠喊话交流。
特点:
所有CPU共享同一块内存和同一套磁盘
像一台电脑插了多个CPU
优点:简单,协调容易(数据都在眼皮底下)
缺点:
大桌子(内存总线)太挤,人多了就堵
文件柜(磁盘)排队严重
扩展性差:加人(CPU)效果越来越差
实际应用:小型服务器、老式数据库机
- 共享磁盘(部分独立)
场景:每人有自己的小办公桌(私有内存),但共享同一个公共文件柜(磁盘),需要时去柜子取文件。
特点:
每个CPU有私有内存,但共享同一套磁盘系统
像多台电脑连同一个网络存储(SAN)
优点:
避免内存争抢(各自有桌子)
方便扩展CPU
磁盘坏了影响所有人
缺点:
抢文件柜:磁盘和网络易成瓶颈
缓存同步麻烦:各自内存里的数据可能不一致
实际应用:Oracle RAC(集群数据库)
- 无共享(最独立)
场景:每人有独立办公室,里面有自己的桌子、文件柜和电话,只通过网络沟通。
特点:
每个CPU有私有内存+私有磁盘
完全不共享硬件,只通过网络通信
像分布式系统
优点:
扩展性极好:加人加办公室就行
没有硬件瓶颈
缺点:
协调复杂:数据分散,需要精心分配
网络通信开销大
一个办公室坏了,部分数据访问不了
实际应用:大数据系统(Hadoop)、现代分布式数据库(Google Spanner、CockroachDB)
- 层次式(混合型)
场景:多个小团队(每个团队内共享内存或磁盘),团队之间通过网络协作。
特点:以上三种的混合体
比如:小组内“共享内存”,小组间“无共享”
优点:灵活,平衡扩展性和复杂度
缺点:设计复杂

怎么记?看“共享什么硬件”
共享内存 → 内存和磁盘都共享(全共享)
共享磁盘 → 只共享磁盘,内存不共享(半共享)
无共享 → 什么都不共享(全独立)
层次式 → 爱怎么混就怎么混(混合体)
要简单便宜、数据量不大 → 共享内存
要高可用、不怕磁盘瓶颈 → 共享磁盘
要海量数据、疯狂扩展 → 无共享
要平衡复杂度和性能 → 层次式
实际中:互联网公司基本都用 无共享 架构(因为数据太大、机器太多)。
事务调度
核心问题
你有一堆事务要执行,怎么安排顺序?
两种基本调度方式
- 串行调度
场景:单车道收费站,一次只过一辆车。
做法:一个事务完全执行完,再执行下一个。
优点:绝对安全,不会出错。
缺点:效率低,资源闲置。
举例:先执行完“张三转账给李四”,再执行“查询余额”。 - 并发调度
场景:多车道收费站,多辆车同时过。
做法:多个事务的操作交错执行。
优点:效率高,资源利用率高。
缺点:可能出错(出现脏读、丢更新等问题)。
举例:“张三转账”和“查询余额”的操作可能交替进行。
调度的最高标准:可串行化调度
这是并发调度的“黄金标准”。
什么是可串行化调度?
翻译成人话:
虽然事务是并发交错执行的,但最终结果和按某种顺序串行执行的结果完全一样。
数据库只接受两种调度:
串行调度(太慢,一般不用)
可串行化调度(又快又对,理想目标)
所有非可串行化的并发调度,数据库都认为是有问题的!
如何实现可串行化调度?
数据库有两大工具:
- 锁机制(特别是两段锁协议)
做法:事务在扩展阶段只能加锁,在收缩阶段只能解锁。
效果:只要所有事务都遵守两段锁协议,调度就一定是可串行化的。 - 冲突可串行化(更常用的判断标准)
关键概念:冲突操作
两个操作来自不同事务
操作同一数据项
至少有一个是写操作
串行调度是为了确保事务的一致性,实现一致性的办法是保证隔离性
评论