MySQL 事务:从一笔转账说起,一文把 ACID、隔离级别、MVCC、锁全串起来
想象一个再平常不过的场景:你给朋友转 100 块钱。
在数据库里,这件事要分成两步------你的账户扣 100,朋友的账户加 100。
可如果刚扣完你的钱,数据库突然宕机了,朋友那边没加上,这 100 块钱去哪了?凭空蒸发了?
再比如,转账过程中,恰好有人同时查你的余额------他会不会看到「扣了钱但还没加钱」的中间状态,以为你账户出了问题?
这些问题,全都要靠一个词来兜底:事务(Transaction)。
一、什么是事务?从一笔转账说起
事务,就是「一组操作,要么全部成功,要么全部失败」的保证。
回到转账的例子,这两步必须被绑在一起:
#mermaid-svg-4v1xGaRS6hYAscrT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4v1xGaRS6hYAscrT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4v1xGaRS6hYAscrT .error-icon{fill:#552222;}#mermaid-svg-4v1xGaRS6hYAscrT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4v1xGaRS6hYAscrT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4v1xGaRS6hYAscrT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4v1xGaRS6hYAscrT .marker.cross{stroke:#333333;}#mermaid-svg-4v1xGaRS6hYAscrT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4v1xGaRS6hYAscrT p{margin:0;}#mermaid-svg-4v1xGaRS6hYAscrT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4v1xGaRS6hYAscrT .cluster-label text{fill:#333;}#mermaid-svg-4v1xGaRS6hYAscrT .cluster-label span{color:#333;}#mermaid-svg-4v1xGaRS6hYAscrT .cluster-label span p{background-color:transparent;}#mermaid-svg-4v1xGaRS6hYAscrT .label text,#mermaid-svg-4v1xGaRS6hYAscrT span{fill:#333;color:#333;}#mermaid-svg-4v1xGaRS6hYAscrT .node rect,#mermaid-svg-4v1xGaRS6hYAscrT .node circle,#mermaid-svg-4v1xGaRS6hYAscrT .node ellipse,#mermaid-svg-4v1xGaRS6hYAscrT .node polygon,#mermaid-svg-4v1xGaRS6hYAscrT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4v1xGaRS6hYAscrT .rough-node .label text,#mermaid-svg-4v1xGaRS6hYAscrT .node .label text,#mermaid-svg-4v1xGaRS6hYAscrT .image-shape .label,#mermaid-svg-4v1xGaRS6hYAscrT .icon-shape .label{text-anchor:middle;}#mermaid-svg-4v1xGaRS6hYAscrT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4v1xGaRS6hYAscrT .rough-node .label,#mermaid-svg-4v1xGaRS6hYAscrT .node .label,#mermaid-svg-4v1xGaRS6hYAscrT .image-shape .label,#mermaid-svg-4v1xGaRS6hYAscrT .icon-shape .label{text-align:center;}#mermaid-svg-4v1xGaRS6hYAscrT .node.clickable{cursor:pointer;}#mermaid-svg-4v1xGaRS6hYAscrT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4v1xGaRS6hYAscrT .arrowheadPath{fill:#333333;}#mermaid-svg-4v1xGaRS6hYAscrT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4v1xGaRS6hYAscrT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4v1xGaRS6hYAscrT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4v1xGaRS6hYAscrT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4v1xGaRS6hYAscrT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4v1xGaRS6hYAscrT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4v1xGaRS6hYAscrT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4v1xGaRS6hYAscrT .cluster text{fill:#333;}#mermaid-svg-4v1xGaRS6hYAscrT .cluster span{color:#333;}#mermaid-svg-4v1xGaRS6hYAscrT 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-4v1xGaRS6hYAscrT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4v1xGaRS6hYAscrT rect.text{fill:none;stroke-width:0;}#mermaid-svg-4v1xGaRS6hYAscrT .icon-shape,#mermaid-svg-4v1xGaRS6hYAscrT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4v1xGaRS6hYAscrT .icon-shape p,#mermaid-svg-4v1xGaRS6hYAscrT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4v1xGaRS6hYAscrT .icon-shape .label rect,#mermaid-svg-4v1xGaRS6hYAscrT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4v1xGaRS6hYAscrT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4v1xGaRS6hYAscrT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4v1xGaRS6hYAscrT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
开始事务
① 你的账户 -100
② 朋友的账户 +100
都成功了?
提交(Commit)
两个改动都生效
回滚(Rollback)
两个改动都撤销
如果没有事务,第一步成功、第二步失败,钱就丢了;有了事务,要么「扣了也加了」,要么「都回滚,就当没发生过」。
一句话 :事务把一堆零散的 SQL,打包成一个「不可分割的整体」。要么一起成,要么一起亡。
在 MySQL 里,事务是由「存储引擎」提供的。只有 InnoDB 引擎支持完整的事务(这也是现在默认用 InnoDB 的重要原因),老旧的 MyISAM 是不支持事务的。
二、ACID:事务的四大特性
事务之所以可靠,靠的是四个特性,合称 ACID。
| 特性 | 全称 | 通俗解释 | 生活类比 |
|---|---|---|---|
| A | Atomicity 原子性 | 要么全做,要么全不做 | 转账:扣钱和加钱绑死 |
| C | Consistency 一致性 | 事务前后,数据都符合规则 | 钱的总数始终不变 |
| I | Isolation 隔离性 | 事务之间互不干扰 | 别人看不到你改到一半 |
| D | Durability 持久性 | 提交后永久保存,不丢 | 钱到账了就是到账了 |
#mermaid-svg-yRVLGEe8aGWy68UL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yRVLGEe8aGWy68UL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yRVLGEe8aGWy68UL .error-icon{fill:#552222;}#mermaid-svg-yRVLGEe8aGWy68UL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yRVLGEe8aGWy68UL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yRVLGEe8aGWy68UL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yRVLGEe8aGWy68UL .marker.cross{stroke:#333333;}#mermaid-svg-yRVLGEe8aGWy68UL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yRVLGEe8aGWy68UL p{margin:0;}#mermaid-svg-yRVLGEe8aGWy68UL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yRVLGEe8aGWy68UL .cluster-label text{fill:#333;}#mermaid-svg-yRVLGEe8aGWy68UL .cluster-label span{color:#333;}#mermaid-svg-yRVLGEe8aGWy68UL .cluster-label span p{background-color:transparent;}#mermaid-svg-yRVLGEe8aGWy68UL .label text,#mermaid-svg-yRVLGEe8aGWy68UL span{fill:#333;color:#333;}#mermaid-svg-yRVLGEe8aGWy68UL .node rect,#mermaid-svg-yRVLGEe8aGWy68UL .node circle,#mermaid-svg-yRVLGEe8aGWy68UL .node ellipse,#mermaid-svg-yRVLGEe8aGWy68UL .node polygon,#mermaid-svg-yRVLGEe8aGWy68UL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yRVLGEe8aGWy68UL .rough-node .label text,#mermaid-svg-yRVLGEe8aGWy68UL .node .label text,#mermaid-svg-yRVLGEe8aGWy68UL .image-shape .label,#mermaid-svg-yRVLGEe8aGWy68UL .icon-shape .label{text-anchor:middle;}#mermaid-svg-yRVLGEe8aGWy68UL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yRVLGEe8aGWy68UL .rough-node .label,#mermaid-svg-yRVLGEe8aGWy68UL .node .label,#mermaid-svg-yRVLGEe8aGWy68UL .image-shape .label,#mermaid-svg-yRVLGEe8aGWy68UL .icon-shape .label{text-align:center;}#mermaid-svg-yRVLGEe8aGWy68UL .node.clickable{cursor:pointer;}#mermaid-svg-yRVLGEe8aGWy68UL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yRVLGEe8aGWy68UL .arrowheadPath{fill:#333333;}#mermaid-svg-yRVLGEe8aGWy68UL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yRVLGEe8aGWy68UL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yRVLGEe8aGWy68UL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yRVLGEe8aGWy68UL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yRVLGEe8aGWy68UL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yRVLGEe8aGWy68UL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yRVLGEe8aGWy68UL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yRVLGEe8aGWy68UL .cluster text{fill:#333;}#mermaid-svg-yRVLGEe8aGWy68UL .cluster span{color:#333;}#mermaid-svg-yRVLGEe8aGWy68UL 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-yRVLGEe8aGWy68UL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yRVLGEe8aGWy68UL rect.text{fill:none;stroke-width:0;}#mermaid-svg-yRVLGEe8aGWy68UL .icon-shape,#mermaid-svg-yRVLGEe8aGWy68UL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yRVLGEe8aGWy68UL .icon-shape p,#mermaid-svg-yRVLGEe8aGWy68UL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yRVLGEe8aGWy68UL .icon-shape .label rect,#mermaid-svg-yRVLGEe8aGWy68UL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yRVLGEe8aGWy68UL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yRVLGEe8aGWy68UL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yRVLGEe8aGWy68UL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 靠回滚保证
靠锁 + MVCC
靠重做日志
ACID 四大特性
原子性
Atomicity
一致性
Consistency
隔离性
Isolation
持久性
Durability
undo log
锁 / MVCC
redo log
一句话 :ACID 四兄弟里,原子性靠回滚日志(undo log)兜底,持久性靠重做日志(redo log)兜底,隔离性靠锁和 MVCC 兜底。
三、没有隔离会怎样?三大并发问题
事务之间的「隔离性」如果做不好,就会出现三个经典的并发问题。搞懂它们,是理解隔离级别的前提。
假设有两个事务同时操作同一行数据:
3.1 脏读(Dirty Read)
读到了别人「还没提交」的、可能回滚的脏数据。
事务 B 事务 A 事务 B 事务 A #mermaid-svg-fQpfBj2A8Eq56Cmo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fQpfBj2A8Eq56Cmo .error-icon{fill:#552222;}#mermaid-svg-fQpfBj2A8Eq56Cmo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fQpfBj2A8Eq56Cmo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fQpfBj2A8Eq56Cmo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fQpfBj2A8Eq56Cmo .marker.cross{stroke:#333333;}#mermaid-svg-fQpfBj2A8Eq56Cmo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fQpfBj2A8Eq56Cmo p{margin:0;}#mermaid-svg-fQpfBj2A8Eq56Cmo .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fQpfBj2A8Eq56Cmo text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fQpfBj2A8Eq56Cmo .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-fQpfBj2A8Eq56Cmo .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-fQpfBj2A8Eq56Cmo #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-fQpfBj2A8Eq56Cmo .sequenceNumber{fill:white;}#mermaid-svg-fQpfBj2A8Eq56Cmo #sequencenumber{fill:#333;}#mermaid-svg-fQpfBj2A8Eq56Cmo #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-fQpfBj2A8Eq56Cmo .messageText{fill:#333;stroke:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fQpfBj2A8Eq56Cmo .labelText,#mermaid-svg-fQpfBj2A8Eq56Cmo .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .loopText,#mermaid-svg-fQpfBj2A8Eq56Cmo .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-fQpfBj2A8Eq56Cmo .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-fQpfBj2A8Eq56Cmo .noteText,#mermaid-svg-fQpfBj2A8Eq56Cmo .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-fQpfBj2A8Eq56Cmo .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fQpfBj2A8Eq56Cmo .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fQpfBj2A8Eq56Cmo .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-fQpfBj2A8Eq56Cmo .actorPopupMenu{position:absolute;}#mermaid-svg-fQpfBj2A8Eq56Cmo .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-fQpfBj2A8Eq56Cmo .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-fQpfBj2A8Eq56Cmo .actor-man circle,#mermaid-svg-fQpfBj2A8Eq56Cmo line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-fQpfBj2A8Eq56Cmo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} B 读到的是「脏数据」那 500 根本不存在 余额改为 500(未提交)读到余额 = 500回滚,余额回到 100
3.2 不可重复读(Non-Repeatable Read)
同一事务内,两次读同一行,结果不一样(因为别人在中间提交了修改)。
事务 B 事务 A 事务 B 事务 A #mermaid-svg-26AlUzIRUyHesZWu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-26AlUzIRUyHesZWu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-26AlUzIRUyHesZWu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-26AlUzIRUyHesZWu .error-icon{fill:#552222;}#mermaid-svg-26AlUzIRUyHesZWu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-26AlUzIRUyHesZWu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-26AlUzIRUyHesZWu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-26AlUzIRUyHesZWu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-26AlUzIRUyHesZWu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-26AlUzIRUyHesZWu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-26AlUzIRUyHesZWu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-26AlUzIRUyHesZWu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-26AlUzIRUyHesZWu .marker.cross{stroke:#333333;}#mermaid-svg-26AlUzIRUyHesZWu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-26AlUzIRUyHesZWu p{margin:0;}#mermaid-svg-26AlUzIRUyHesZWu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-26AlUzIRUyHesZWu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-26AlUzIRUyHesZWu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-26AlUzIRUyHesZWu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-26AlUzIRUyHesZWu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-26AlUzIRUyHesZWu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-26AlUzIRUyHesZWu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-26AlUzIRUyHesZWu .sequenceNumber{fill:white;}#mermaid-svg-26AlUzIRUyHesZWu #sequencenumber{fill:#333;}#mermaid-svg-26AlUzIRUyHesZWu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-26AlUzIRUyHesZWu .messageText{fill:#333;stroke:none;}#mermaid-svg-26AlUzIRUyHesZWu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-26AlUzIRUyHesZWu .labelText,#mermaid-svg-26AlUzIRUyHesZWu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-26AlUzIRUyHesZWu .loopText,#mermaid-svg-26AlUzIRUyHesZWu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-26AlUzIRUyHesZWu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-26AlUzIRUyHesZWu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-26AlUzIRUyHesZWu .noteText,#mermaid-svg-26AlUzIRUyHesZWu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-26AlUzIRUyHesZWu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-26AlUzIRUyHesZWu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-26AlUzIRUyHesZWu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-26AlUzIRUyHesZWu .actorPopupMenu{position:absolute;}#mermaid-svg-26AlUzIRUyHesZWu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-26AlUzIRUyHesZWu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-26AlUzIRUyHesZWu .actor-man circle,#mermaid-svg-26AlUzIRUyHesZWu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-26AlUzIRUyHesZWu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 两次读不一样,「重复读」失败 第一次读余额 = 100把余额改成 500 并提交第二次读余额 = 500
3.3 幻读(Phantom Read)
同一事务内,两次查询「符合条件的行数」不一样(因为别人在中间插入了新数据)。
事务 B 事务 A 事务 B 事务 A #mermaid-svg-HV0KSpm1pTlRQcyN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HV0KSpm1pTlRQcyN .error-icon{fill:#552222;}#mermaid-svg-HV0KSpm1pTlRQcyN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HV0KSpm1pTlRQcyN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HV0KSpm1pTlRQcyN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HV0KSpm1pTlRQcyN .marker.cross{stroke:#333333;}#mermaid-svg-HV0KSpm1pTlRQcyN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HV0KSpm1pTlRQcyN p{margin:0;}#mermaid-svg-HV0KSpm1pTlRQcyN .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-HV0KSpm1pTlRQcyN text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-HV0KSpm1pTlRQcyN .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-HV0KSpm1pTlRQcyN .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-HV0KSpm1pTlRQcyN #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-HV0KSpm1pTlRQcyN .sequenceNumber{fill:white;}#mermaid-svg-HV0KSpm1pTlRQcyN #sequencenumber{fill:#333;}#mermaid-svg-HV0KSpm1pTlRQcyN #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-HV0KSpm1pTlRQcyN .messageText{fill:#333;stroke:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-HV0KSpm1pTlRQcyN .labelText,#mermaid-svg-HV0KSpm1pTlRQcyN .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .loopText,#mermaid-svg-HV0KSpm1pTlRQcyN .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-HV0KSpm1pTlRQcyN .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-HV0KSpm1pTlRQcyN .noteText,#mermaid-svg-HV0KSpm1pTlRQcyN .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-HV0KSpm1pTlRQcyN .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-HV0KSpm1pTlRQcyN .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-HV0KSpm1pTlRQcyN .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-HV0KSpm1pTlRQcyN .actorPopupMenu{position:absolute;}#mermaid-svg-HV0KSpm1pTlRQcyN .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-HV0KSpm1pTlRQcyN .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-HV0KSpm1pTlRQcyN .actor-man circle,#mermaid-svg-HV0KSpm1pTlRQcyN line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-HV0KSpm1pTlRQcyN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 多出来的那条,像「幻影」一样 查询:金额>100 的用户 → 3 条插入一条金额=200 的记录并提交再查:金额>100 的用户 → 4 条
一句话 :脏读是「读到了没提交的」,不可重复读是「同一行被改了」,幻读是「多出了新的行」。一个比一个更隐蔽,也一个比一个更难解决。
四、四大隔离级别:越严越安全,越严越慢
为了解决上面三个问题,SQL 标准定义了四个隔离级别(Isolation Level),从宽松到严格:
#mermaid-svg-PV9mwEG27pA2dBOH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PV9mwEG27pA2dBOH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PV9mwEG27pA2dBOH .error-icon{fill:#552222;}#mermaid-svg-PV9mwEG27pA2dBOH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PV9mwEG27pA2dBOH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PV9mwEG27pA2dBOH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PV9mwEG27pA2dBOH .marker.cross{stroke:#333333;}#mermaid-svg-PV9mwEG27pA2dBOH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PV9mwEG27pA2dBOH p{margin:0;}#mermaid-svg-PV9mwEG27pA2dBOH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PV9mwEG27pA2dBOH .cluster-label text{fill:#333;}#mermaid-svg-PV9mwEG27pA2dBOH .cluster-label span{color:#333;}#mermaid-svg-PV9mwEG27pA2dBOH .cluster-label span p{background-color:transparent;}#mermaid-svg-PV9mwEG27pA2dBOH .label text,#mermaid-svg-PV9mwEG27pA2dBOH span{fill:#333;color:#333;}#mermaid-svg-PV9mwEG27pA2dBOH .node rect,#mermaid-svg-PV9mwEG27pA2dBOH .node circle,#mermaid-svg-PV9mwEG27pA2dBOH .node ellipse,#mermaid-svg-PV9mwEG27pA2dBOH .node polygon,#mermaid-svg-PV9mwEG27pA2dBOH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PV9mwEG27pA2dBOH .rough-node .label text,#mermaid-svg-PV9mwEG27pA2dBOH .node .label text,#mermaid-svg-PV9mwEG27pA2dBOH .image-shape .label,#mermaid-svg-PV9mwEG27pA2dBOH .icon-shape .label{text-anchor:middle;}#mermaid-svg-PV9mwEG27pA2dBOH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PV9mwEG27pA2dBOH .rough-node .label,#mermaid-svg-PV9mwEG27pA2dBOH .node .label,#mermaid-svg-PV9mwEG27pA2dBOH .image-shape .label,#mermaid-svg-PV9mwEG27pA2dBOH .icon-shape .label{text-align:center;}#mermaid-svg-PV9mwEG27pA2dBOH .node.clickable{cursor:pointer;}#mermaid-svg-PV9mwEG27pA2dBOH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PV9mwEG27pA2dBOH .arrowheadPath{fill:#333333;}#mermaid-svg-PV9mwEG27pA2dBOH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PV9mwEG27pA2dBOH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PV9mwEG27pA2dBOH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PV9mwEG27pA2dBOH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PV9mwEG27pA2dBOH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PV9mwEG27pA2dBOH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PV9mwEG27pA2dBOH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PV9mwEG27pA2dBOH .cluster text{fill:#333;}#mermaid-svg-PV9mwEG27pA2dBOH .cluster span{color:#333;}#mermaid-svg-PV9mwEG27pA2dBOH 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-PV9mwEG27pA2dBOH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PV9mwEG27pA2dBOH rect.text{fill:none;stroke-width:0;}#mermaid-svg-PV9mwEG27pA2dBOH .icon-shape,#mermaid-svg-PV9mwEG27pA2dBOH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PV9mwEG27pA2dBOH .icon-shape p,#mermaid-svg-PV9mwEG27pA2dBOH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PV9mwEG27pA2dBOH .icon-shape .label rect,#mermaid-svg-PV9mwEG27pA2dBOH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PV9mwEG27pA2dBOH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PV9mwEG27pA2dBOH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PV9mwEG27pA2dBOH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 读未提交
Read Uncommitted
读已提交
Read Committed
可重复读
Repeatable Read
串行化
Serializable
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 并发性能 |
|---|---|---|---|---|
| 读未提交 | ❌ 会发生 | ❌ 会发生 | ❌ 会发生 | 最高 |
| 读已提交 | ✅ 解决 | ❌ 会发生 | ❌ 会发生 | 较高 |
| 可重复读(MySQL 默认) | ✅ 解决 | ✅ 解决 | ⚠️ 大部分解决 | 中等 |
| 串行化 | ✅ 解决 | ✅ 解决 | ✅ 解决 | 最低 |
几个关键点要记住:
- MySQL 默认是「可重复读(Repeatable Read)」,这和很多教材写的「默认读已提交」不一样(那是 Oracle 等数据库);
- 「可重复读」在 InnoDB 里,通过 MVCC + 间隙锁,幻读也基本被解决了,所以实际表现比理论表格更强;
- 级别越高越安全,但并发越差、锁越多、越慢。不是越严越好,要按业务选。
text
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别(会话级)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
五、MVCC:读不阻塞写的秘密
你可能会疑惑:MySQL 默认「可重复读」,那它是怎么做到「我读的时候,别人还能同时写」的?答案是一个很精妙的设计------MVCC(多版本并发控制)。
5.1 核心思想
MVCC 的核心就一句话:读操作不直接读「正在被改的那份数据」,而是读「历史快照」。
它不给数据「上锁」,而是给每行数据保留多个版本:
#mermaid-svg-jqHKbSrZ3uaYAFr9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .error-icon{fill:#552222;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .marker.cross{stroke:#333333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 p{margin:0;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .cluster-label text{fill:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .cluster-label span{color:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .cluster-label span p{background-color:transparent;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .label text,#mermaid-svg-jqHKbSrZ3uaYAFr9 span{fill:#333;color:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .node rect,#mermaid-svg-jqHKbSrZ3uaYAFr9 .node circle,#mermaid-svg-jqHKbSrZ3uaYAFr9 .node ellipse,#mermaid-svg-jqHKbSrZ3uaYAFr9 .node polygon,#mermaid-svg-jqHKbSrZ3uaYAFr9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .rough-node .label text,#mermaid-svg-jqHKbSrZ3uaYAFr9 .node .label text,#mermaid-svg-jqHKbSrZ3uaYAFr9 .image-shape .label,#mermaid-svg-jqHKbSrZ3uaYAFr9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .rough-node .label,#mermaid-svg-jqHKbSrZ3uaYAFr9 .node .label,#mermaid-svg-jqHKbSrZ3uaYAFr9 .image-shape .label,#mermaid-svg-jqHKbSrZ3uaYAFr9 .icon-shape .label{text-align:center;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .node.clickable{cursor:pointer;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .arrowheadPath{fill:#333333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jqHKbSrZ3uaYAFr9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jqHKbSrZ3uaYAFr9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jqHKbSrZ3uaYAFr9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .cluster text{fill:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .cluster span{color:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 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-jqHKbSrZ3uaYAFr9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jqHKbSrZ3uaYAFr9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .icon-shape,#mermaid-svg-jqHKbSrZ3uaYAFr9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .icon-shape p,#mermaid-svg-jqHKbSrZ3uaYAFr9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .icon-shape .label rect,#mermaid-svg-jqHKbSrZ3uaYAFr9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jqHKbSrZ3uaYAFr9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jqHKbSrZ3uaYAFr9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jqHKbSrZ3uaYAFr9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 读快照 → 拿到 100
写新版本
互不阻塞
一行数据
版本 1
(旧值 100)
版本 2
(新值 500,未提交)
事务 A 读
事务 B 写
- 写事务:不改旧数据,而是新建一个「新版本」;
- 读事务:根据自己开启时的「快照」,读到自己该看到的那个版本。
这样,读和写互不阻塞,大大提升了并发能力。
5.2 快照是怎么实现的?
MVCC 的实现,靠两个隐藏字段 + 一个日志:
| 机制 | 作用 |
|---|---|
| 隐藏字段(事务 ID、回滚指针) | 标记每一行的版本信息 |
| undo log(回滚日志) | 保存历史版本,供快照读取和回滚 |
#mermaid-svg-0dYVSNKlmMZ3p6Wt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .error-icon{fill:#552222;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .marker.cross{stroke:#333333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt p{margin:0;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .cluster-label text{fill:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .cluster-label span{color:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .cluster-label span p{background-color:transparent;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .label text,#mermaid-svg-0dYVSNKlmMZ3p6Wt span{fill:#333;color:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .node rect,#mermaid-svg-0dYVSNKlmMZ3p6Wt .node circle,#mermaid-svg-0dYVSNKlmMZ3p6Wt .node ellipse,#mermaid-svg-0dYVSNKlmMZ3p6Wt .node polygon,#mermaid-svg-0dYVSNKlmMZ3p6Wt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .rough-node .label text,#mermaid-svg-0dYVSNKlmMZ3p6Wt .node .label text,#mermaid-svg-0dYVSNKlmMZ3p6Wt .image-shape .label,#mermaid-svg-0dYVSNKlmMZ3p6Wt .icon-shape .label{text-anchor:middle;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .rough-node .label,#mermaid-svg-0dYVSNKlmMZ3p6Wt .node .label,#mermaid-svg-0dYVSNKlmMZ3p6Wt .image-shape .label,#mermaid-svg-0dYVSNKlmMZ3p6Wt .icon-shape .label{text-align:center;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .node.clickable{cursor:pointer;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .arrowheadPath{fill:#333333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0dYVSNKlmMZ3p6Wt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0dYVSNKlmMZ3p6Wt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0dYVSNKlmMZ3p6Wt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .cluster text{fill:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .cluster span{color:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt 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-0dYVSNKlmMZ3p6Wt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0dYVSNKlmMZ3p6Wt rect.text{fill:none;stroke-width:0;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .icon-shape,#mermaid-svg-0dYVSNKlmMZ3p6Wt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .icon-shape p,#mermaid-svg-0dYVSNKlmMZ3p6Wt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .icon-shape .label rect,#mermaid-svg-0dYVSNKlmMZ3p6Wt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0dYVSNKlmMZ3p6Wt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0dYVSNKlmMZ3p6Wt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0dYVSNKlmMZ3p6Wt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 回滚指针
回滚指针
当前版本
(余额=500,事务 ID=200)
历史版本
(余额=100,事务 ID=100)
更早版本
(余额=80)
通过这条「版本链」,一个事务就能在「当前值 500」的前提下,依然读到自己快照对应的「历史值 100」。
一句话 :MVCC 的本质是「用空间换并发」------多存几个历史版本,让读操作永远有「过去的版本」可读,从而不用和写操作抢锁。这也是「可重复读」能既安全又不太慢的根本原因。
六、锁:事务的物理防线
MVCC 解决了「读」,但「写」之间还是会冲突的------两个事务不能同时改同一行。这时候,就轮到**锁(Lock)**上场了。
6.1 按范围分:表锁 vs 行锁
| 锁类型 | 锁住什么 | 特点 |
|---|---|---|
| 表锁 | 整张表 | 简单粗暴,并发差 |
| 行锁 | 某几行 | 粒度细,并发好(InnoDB 默认) |
InnoDB 用的是行锁,所以高并发场景下性能更好。
6.2 按模式分:共享锁 vs 排他锁
| 锁模式 | 简称 | 能干什么 | 谁和谁互斥 |
|---|---|---|---|
| 共享锁 | S 锁 | 读 | 和排他锁互斥,和共享锁兼容 |
| 排他锁 | X 锁 | 写 | 和谁都互斥 |
6.3 死锁:两个事务互相等对方
锁的经典事故就是死锁:
#mermaid-svg-cBfxHZr55RKTlPu1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cBfxHZr55RKTlPu1 .error-icon{fill:#552222;}#mermaid-svg-cBfxHZr55RKTlPu1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cBfxHZr55RKTlPu1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cBfxHZr55RKTlPu1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cBfxHZr55RKTlPu1 .marker.cross{stroke:#333333;}#mermaid-svg-cBfxHZr55RKTlPu1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cBfxHZr55RKTlPu1 p{margin:0;}#mermaid-svg-cBfxHZr55RKTlPu1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 .cluster-label text{fill:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 .cluster-label span{color:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 .cluster-label span p{background-color:transparent;}#mermaid-svg-cBfxHZr55RKTlPu1 .label text,#mermaid-svg-cBfxHZr55RKTlPu1 span{fill:#333;color:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 .node rect,#mermaid-svg-cBfxHZr55RKTlPu1 .node circle,#mermaid-svg-cBfxHZr55RKTlPu1 .node ellipse,#mermaid-svg-cBfxHZr55RKTlPu1 .node polygon,#mermaid-svg-cBfxHZr55RKTlPu1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cBfxHZr55RKTlPu1 .rough-node .label text,#mermaid-svg-cBfxHZr55RKTlPu1 .node .label text,#mermaid-svg-cBfxHZr55RKTlPu1 .image-shape .label,#mermaid-svg-cBfxHZr55RKTlPu1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-cBfxHZr55RKTlPu1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cBfxHZr55RKTlPu1 .rough-node .label,#mermaid-svg-cBfxHZr55RKTlPu1 .node .label,#mermaid-svg-cBfxHZr55RKTlPu1 .image-shape .label,#mermaid-svg-cBfxHZr55RKTlPu1 .icon-shape .label{text-align:center;}#mermaid-svg-cBfxHZr55RKTlPu1 .node.clickable{cursor:pointer;}#mermaid-svg-cBfxHZr55RKTlPu1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cBfxHZr55RKTlPu1 .arrowheadPath{fill:#333333;}#mermaid-svg-cBfxHZr55RKTlPu1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cBfxHZr55RKTlPu1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cBfxHZr55RKTlPu1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cBfxHZr55RKTlPu1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cBfxHZr55RKTlPu1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cBfxHZr55RKTlPu1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cBfxHZr55RKTlPu1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cBfxHZr55RKTlPu1 .cluster text{fill:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 .cluster span{color:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 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-cBfxHZr55RKTlPu1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cBfxHZr55RKTlPu1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-cBfxHZr55RKTlPu1 .icon-shape,#mermaid-svg-cBfxHZr55RKTlPu1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cBfxHZr55RKTlPu1 .icon-shape p,#mermaid-svg-cBfxHZr55RKTlPu1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cBfxHZr55RKTlPu1 .icon-shape .label rect,#mermaid-svg-cBfxHZr55RKTlPu1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cBfxHZr55RKTlPu1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cBfxHZr55RKTlPu1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cBfxHZr55RKTlPu1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 等待
等待
事务 A:
锁了 1 号行,等着 2 号行
事务 B:
锁了 2 号行,等着 1 号行
两个事务互相拿着对方要的锁,谁也不放,僵住了。MySQL 会自动检测死锁,强制回滚其中一个事务来破局。
一句话:MVCC 管「读」,锁管「写」。锁是事务的「物理防线」,但用不好就会造成阻塞和死锁------这也是「为什么数据库有时会莫名其妙卡住」的根源。
七、事务的传播行为(Spring 里的事)
我们实际写代码,大多通过 Spring 的 @Transactional 来用事务。这里有个概念特别容易搞混,但必须懂:事务的传播行为(Propagation)。
它回答的问题是:一个事务方法,调用了另一个事务方法,这俩事务是什么关系?
#mermaid-svg-iPje2V6KHpP9tS0q{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iPje2V6KHpP9tS0q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iPje2V6KHpP9tS0q .error-icon{fill:#552222;}#mermaid-svg-iPje2V6KHpP9tS0q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iPje2V6KHpP9tS0q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iPje2V6KHpP9tS0q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iPje2V6KHpP9tS0q .marker.cross{stroke:#333333;}#mermaid-svg-iPje2V6KHpP9tS0q svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iPje2V6KHpP9tS0q p{margin:0;}#mermaid-svg-iPje2V6KHpP9tS0q .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iPje2V6KHpP9tS0q .cluster-label text{fill:#333;}#mermaid-svg-iPje2V6KHpP9tS0q .cluster-label span{color:#333;}#mermaid-svg-iPje2V6KHpP9tS0q .cluster-label span p{background-color:transparent;}#mermaid-svg-iPje2V6KHpP9tS0q .label text,#mermaid-svg-iPje2V6KHpP9tS0q span{fill:#333;color:#333;}#mermaid-svg-iPje2V6KHpP9tS0q .node rect,#mermaid-svg-iPje2V6KHpP9tS0q .node circle,#mermaid-svg-iPje2V6KHpP9tS0q .node ellipse,#mermaid-svg-iPje2V6KHpP9tS0q .node polygon,#mermaid-svg-iPje2V6KHpP9tS0q .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iPje2V6KHpP9tS0q .rough-node .label text,#mermaid-svg-iPje2V6KHpP9tS0q .node .label text,#mermaid-svg-iPje2V6KHpP9tS0q .image-shape .label,#mermaid-svg-iPje2V6KHpP9tS0q .icon-shape .label{text-anchor:middle;}#mermaid-svg-iPje2V6KHpP9tS0q .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iPje2V6KHpP9tS0q .rough-node .label,#mermaid-svg-iPje2V6KHpP9tS0q .node .label,#mermaid-svg-iPje2V6KHpP9tS0q .image-shape .label,#mermaid-svg-iPje2V6KHpP9tS0q .icon-shape .label{text-align:center;}#mermaid-svg-iPje2V6KHpP9tS0q .node.clickable{cursor:pointer;}#mermaid-svg-iPje2V6KHpP9tS0q .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iPje2V6KHpP9tS0q .arrowheadPath{fill:#333333;}#mermaid-svg-iPje2V6KHpP9tS0q .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iPje2V6KHpP9tS0q .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iPje2V6KHpP9tS0q .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iPje2V6KHpP9tS0q .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iPje2V6KHpP9tS0q .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iPje2V6KHpP9tS0q .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iPje2V6KHpP9tS0q .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iPje2V6KHpP9tS0q .cluster text{fill:#333;}#mermaid-svg-iPje2V6KHpP9tS0q .cluster span{color:#333;}#mermaid-svg-iPje2V6KHpP9tS0q 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-iPje2V6KHpP9tS0q .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iPje2V6KHpP9tS0q rect.text{fill:none;stroke-width:0;}#mermaid-svg-iPje2V6KHpP9tS0q .icon-shape,#mermaid-svg-iPje2V6KHpP9tS0q .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iPje2V6KHpP9tS0q .icon-shape p,#mermaid-svg-iPje2V6KHpP9tS0q .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iPje2V6KHpP9tS0q .icon-shape .label rect,#mermaid-svg-iPje2V6KHpP9tS0q .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iPje2V6KHpP9tS0q .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iPje2V6KHpP9tS0q .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iPje2V6KHpP9tS0q :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 调用
方法 A(有事务)
方法 B(也有事务)
B 该用哪个事务?
用 A 的事务(一起提交)
新开一个事务(各管各)
不用事务
常见的几种传播行为:
| 传播行为 | 含义 | 通俗说法 |
|---|---|---|
| REQUIRED(默认) | 有就用,没有就新建 | 「随大流」 |
| REQUIRES_NEW | 总是新开一个独立事务 | 「另起炉灶」 |
| SUPPORTS | 有就加入,没有就算了 | 「随缘」 |
| NOT_SUPPORTED | 挂起当前事务,自己不用事务跑 | 「暂时脱离」 |
| MANDATORY | 必须已有事务,否则报错 | 「必须有人带着」 |
| NEVER | 必须没有事务,否则报错 | 「绝不沾事务」 |
一句话 :传播行为解决的是「多个事务方法嵌套时,事务到底听谁的」。默认的 REQUIRED 会「加入已有事务」,这也是「为什么内层方法异常会连累外层一起回滚」的原因。
八、事务失效的常见坑(重点避雷)
@Transactional 看起来简单,但失效的场景多到离谱。这里发散地列出最常踩的几个,都是生产血泪:
| 坑 | 为什么失效 | 解法 |
|---|---|---|
| 同类内部调用 | 自己调自己,绕过了代理 | 拆到不同类,或注入自己 |
| 方法不是 public | Spring 只能代理 public 方法 | 改成 public |
| 异常被 catch 吞掉 | 事务感知不到异常,以为没出错 | 手动 rollback 或抛出 |
| 抛的是受检异常 | 默认只对 RuntimeException 回滚 | 指定 rollbackFor |
| 类没被 Spring 管理 | 自己 new 的,不是 Bean | 交给容器管理 |
| 数据库不支持事务 | 用了 MyISAM 等引擎 | 换成 InnoDB |
其中「异常被吞掉」最隐蔽:
java
@Transactional
public void save() {
try {
dao.insert(); // 这里抛了异常
} catch (Exception e) {
log.error("出错", e); // 被 catch 吞掉了,没往外抛
// 事务不知道出错了 → 不会回滚!
}
}
一句话 :事务失效,99% 的原因都是「Spring 的代理机制没生效 」或「异常没让事务知道」。记住这两条主线,大部分坑都能一眼看穿。
九、大事务的危害与优化
事务不是越大越好。一个「大事务」------比如一个事务里塞了几万条数据、跑了几十秒------是很多性能问题的罪魁祸首。
9.1 大事务的危害
#mermaid-svg-JY0klfuDRD2oQEr8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JY0klfuDRD2oQEr8 .error-icon{fill:#552222;}#mermaid-svg-JY0klfuDRD2oQEr8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JY0klfuDRD2oQEr8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JY0klfuDRD2oQEr8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JY0klfuDRD2oQEr8 .marker.cross{stroke:#333333;}#mermaid-svg-JY0klfuDRD2oQEr8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JY0klfuDRD2oQEr8 p{margin:0;}#mermaid-svg-JY0klfuDRD2oQEr8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 .cluster-label text{fill:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 .cluster-label span{color:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 .cluster-label span p{background-color:transparent;}#mermaid-svg-JY0klfuDRD2oQEr8 .label text,#mermaid-svg-JY0klfuDRD2oQEr8 span{fill:#333;color:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 .node rect,#mermaid-svg-JY0klfuDRD2oQEr8 .node circle,#mermaid-svg-JY0klfuDRD2oQEr8 .node ellipse,#mermaid-svg-JY0klfuDRD2oQEr8 .node polygon,#mermaid-svg-JY0klfuDRD2oQEr8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JY0klfuDRD2oQEr8 .rough-node .label text,#mermaid-svg-JY0klfuDRD2oQEr8 .node .label text,#mermaid-svg-JY0klfuDRD2oQEr8 .image-shape .label,#mermaid-svg-JY0klfuDRD2oQEr8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-JY0klfuDRD2oQEr8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JY0klfuDRD2oQEr8 .rough-node .label,#mermaid-svg-JY0klfuDRD2oQEr8 .node .label,#mermaid-svg-JY0klfuDRD2oQEr8 .image-shape .label,#mermaid-svg-JY0klfuDRD2oQEr8 .icon-shape .label{text-align:center;}#mermaid-svg-JY0klfuDRD2oQEr8 .node.clickable{cursor:pointer;}#mermaid-svg-JY0klfuDRD2oQEr8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JY0klfuDRD2oQEr8 .arrowheadPath{fill:#333333;}#mermaid-svg-JY0klfuDRD2oQEr8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JY0klfuDRD2oQEr8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JY0klfuDRD2oQEr8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JY0klfuDRD2oQEr8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JY0klfuDRD2oQEr8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JY0klfuDRD2oQEr8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JY0klfuDRD2oQEr8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JY0klfuDRD2oQEr8 .cluster text{fill:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 .cluster span{color:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 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-JY0klfuDRD2oQEr8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JY0klfuDRD2oQEr8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-JY0klfuDRD2oQEr8 .icon-shape,#mermaid-svg-JY0klfuDRD2oQEr8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JY0klfuDRD2oQEr8 .icon-shape p,#mermaid-svg-JY0klfuDRD2oQEr8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JY0klfuDRD2oQEr8 .icon-shape .label rect,#mermaid-svg-JY0klfuDRD2oQEr8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JY0klfuDRD2oQEr8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JY0klfuDRD2oQEr8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JY0klfuDRD2oQEr8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 大事务
锁持有时间长
→ 阻塞别的请求
undo log 膨胀
→ 占用大量空间
回滚代价高
→ 出事回滚很慢
主从延迟
→ 数据一致性风险
9.2 优化的思路
| 思路 | 做法 |
|---|---|
| 缩小事务范围 | 只把「必须原子」的操作放进事务,查询、日志、RPC 移出去 |
| 批量拆分 | 大批量更新,拆成小批量 + 分批提交 |
| 减少锁竞争 | 合理用索引,避免锁全表 |
| 异步化 | 非关键操作,事务提交后再异步处理 |
一句话 :事务越小越好------只包住「必须一起成功或一起失败」的那几行,其余的都挪出去。很多数据库性能问题,不是 SQL 慢,而是「事务太大了」。
十、事务与性能:几个实用建议
最后,发散地给几条「事务用得溜」的实用建议,都是经验之谈:
| 建议 | 说明 |
|---|---|
| 选对隔离级别 | 读多写少可用「读已提交」,别盲目用最严的 |
| 索引要给好 | 行锁需要索引定位,没索引会退化成锁表 |
| 避免长事务 | 事务里别干耗时的事(调外部接口、发邮件) |
| 关注死锁日志 | SHOW ENGINE INNODB STATUS 看死锁,对症下药 |
| 善用只读事务 | 纯查询可以标记为只读,减少开销 |
#mermaid-svg-ZvAS5YEK7822rysY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZvAS5YEK7822rysY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZvAS5YEK7822rysY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZvAS5YEK7822rysY .error-icon{fill:#552222;}#mermaid-svg-ZvAS5YEK7822rysY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZvAS5YEK7822rysY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZvAS5YEK7822rysY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZvAS5YEK7822rysY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZvAS5YEK7822rysY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZvAS5YEK7822rysY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZvAS5YEK7822rysY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZvAS5YEK7822rysY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZvAS5YEK7822rysY .marker.cross{stroke:#333333;}#mermaid-svg-ZvAS5YEK7822rysY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZvAS5YEK7822rysY p{margin:0;}#mermaid-svg-ZvAS5YEK7822rysY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZvAS5YEK7822rysY .cluster-label text{fill:#333;}#mermaid-svg-ZvAS5YEK7822rysY .cluster-label span{color:#333;}#mermaid-svg-ZvAS5YEK7822rysY .cluster-label span p{background-color:transparent;}#mermaid-svg-ZvAS5YEK7822rysY .label text,#mermaid-svg-ZvAS5YEK7822rysY span{fill:#333;color:#333;}#mermaid-svg-ZvAS5YEK7822rysY .node rect,#mermaid-svg-ZvAS5YEK7822rysY .node circle,#mermaid-svg-ZvAS5YEK7822rysY .node ellipse,#mermaid-svg-ZvAS5YEK7822rysY .node polygon,#mermaid-svg-ZvAS5YEK7822rysY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZvAS5YEK7822rysY .rough-node .label text,#mermaid-svg-ZvAS5YEK7822rysY .node .label text,#mermaid-svg-ZvAS5YEK7822rysY .image-shape .label,#mermaid-svg-ZvAS5YEK7822rysY .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZvAS5YEK7822rysY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZvAS5YEK7822rysY .rough-node .label,#mermaid-svg-ZvAS5YEK7822rysY .node .label,#mermaid-svg-ZvAS5YEK7822rysY .image-shape .label,#mermaid-svg-ZvAS5YEK7822rysY .icon-shape .label{text-align:center;}#mermaid-svg-ZvAS5YEK7822rysY .node.clickable{cursor:pointer;}#mermaid-svg-ZvAS5YEK7822rysY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZvAS5YEK7822rysY .arrowheadPath{fill:#333333;}#mermaid-svg-ZvAS5YEK7822rysY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZvAS5YEK7822rysY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZvAS5YEK7822rysY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZvAS5YEK7822rysY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZvAS5YEK7822rysY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZvAS5YEK7822rysY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZvAS5YEK7822rysY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZvAS5YEK7822rysY .cluster text{fill:#333;}#mermaid-svg-ZvAS5YEK7822rysY .cluster span{color:#333;}#mermaid-svg-ZvAS5YEK7822rysY 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-ZvAS5YEK7822rysY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZvAS5YEK7822rysY rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZvAS5YEK7822rysY .icon-shape,#mermaid-svg-ZvAS5YEK7822rysY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZvAS5YEK7822rysY .icon-shape p,#mermaid-svg-ZvAS5YEK7822rysY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZvAS5YEK7822rysY .icon-shape .label rect,#mermaid-svg-ZvAS5YEK7822rysY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZvAS5YEK7822rysY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZvAS5YEK7822rysY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZvAS5YEK7822rysY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 高并发
合理隔离级别
缩小事务
好索引
少锁竞争
又稳又快
写在最后
我们从一笔「转丢的钱」出发,把 MySQL 事务这个「玄学」概念,发散地、完整地过了一遍。回顾这条主线:
- 事务 = 一组操作「要么全成,要么全败」,靠 InnoDB 提供;
- ACID 四大特性:原子性靠 undo log、持久性靠 redo log、隔离性靠锁 + MVCC;
- 三大并发问题:脏读、不可重复读、幻读,一个比一个隐蔽;
- 四大隔离级别:MySQL 默认「可重复读」,越严越安全也越慢;
- MVCC 用「多版本 + 快照」实现读不阻塞写;
- 锁 管写,行锁粒度细,但用不好会死锁;
- 传播行为 决定嵌套事务「听谁的」;
- 事务失效 大多因为代理没生效、或异常没让事务知道;
- 大事务 是性能杀手,越小越好;
- 用好事务,靠「选对级别、给好索引、缩小范围」。