learn.lianglianglee.com/文章/MySQL事务_事务隔离级别详解.md.html
2022-05-11 19:04:14 +08:00

1399 lines
36 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>MySQL事务_事务隔离级别详解.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/文章/AQS 万字图文全面解析.md.html">AQS 万字图文全面解析.md.html</a>
</li>
<li>
<a href="/文章/Docker 镜像构建原理及源码分析.md.html">Docker 镜像构建原理及源码分析.md.html</a>
</li>
<li>
<a href="/文章/ElasticSearch 小白从入门到精通.md.html">ElasticSearch 小白从入门到精通.md.html</a>
</li>
<li>
<a href="/文章/JVM CPU Profiler技术原理及源码深度解析.md.html">JVM CPU Profiler技术原理及源码深度解析.md.html</a>
</li>
<li>
<a href="/文章/JVM 垃圾收集器.md.html">JVM 垃圾收集器.md.html</a>
</li>
<li>
<a href="/文章/JVM 面试的 30 个知识点.md.html">JVM 面试的 30 个知识点.md.html</a>
</li>
<li>
<a href="/文章/Java IO 体系、线程模型大总结.md.html">Java IO 体系、线程模型大总结.md.html</a>
</li>
<li>
<a href="/文章/Java NIO浅析.md.html">Java NIO浅析.md.html</a>
</li>
<li>
<a href="/文章/Java 面试题集锦(网络篇).md.html">Java 面试题集锦(网络篇).md.html</a>
</li>
<li>
<a href="/文章/Java-直接内存 DirectMemory 详解.md.html">Java-直接内存 DirectMemory 详解.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中的SPI.md.html">Java中的SPI.md.html</a>
</li>
<li>
<a href="/文章/Java中的ThreadLocal.md.html">Java中的ThreadLocal.md.html</a>
</li>
<li>
<a href="/文章/Java线程池实现原理及其在美团业务中的实践.md.html">Java线程池实现原理及其在美团业务中的实践.md.html</a>
</li>
<li>
<a href="/文章/Java魔法类Unsafe应用解析.md.html">Java魔法类Unsafe应用解析.md.html</a>
</li>
<li>
<a href="/文章/Kafka 源码阅读笔记.md.html">Kafka 源码阅读笔记.md.html</a>
</li>
<li>
<a href="/文章/Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html">Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB Buffer Pool.md.html">MySQL · 引擎特性 · InnoDB Buffer Pool.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB IO子系统.md.html">MySQL · 引擎特性 · InnoDB IO子系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 事务系统.md.html">MySQL · 引擎特性 · InnoDB 事务系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 同步机制.md.html">MySQL · 引擎特性 · InnoDB 同步机制.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 数据页解析.md.html">MySQL · 引擎特性 · InnoDB 数据页解析.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB崩溃恢复.md.html">MySQL · 引擎特性 · InnoDB崩溃恢复.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · 临时表那些事儿.md.html">MySQL · 引擎特性 · 临时表那些事儿.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 半同步复制.md.html">MySQL 主从复制 半同步复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 基于GTID复制.md.html">MySQL 主从复制 基于GTID复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制.md.html">MySQL 主从复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 事务日志(redo log和undo log).md.html">MySQL 事务日志(redo log和undo log).md.html</a>
</li>
<li>
<a href="/文章/MySQL 亿级别数据迁移实战代码分享.md.html">MySQL 亿级别数据迁移实战代码分享.md.html</a>
</li>
<li>
<a href="/文章/MySQL 从一条数据说起-InnoDB行存储数据结构.md.html">MySQL 从一条数据说起-InnoDB行存储数据结构.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:事务和锁的面纱.md.html">MySQL 地基基础:事务和锁的面纱.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据字典.md.html">MySQL 地基基础:数据字典.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据库字符集.md.html">MySQL 地基基础:数据库字符集.md.html</a>
</li>
<li>
<a href="/文章/MySQL 性能优化:碎片整理.md.html">MySQL 性能优化:碎片整理.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html">MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:如何在日志中轻松定位大事务.md.html">MySQL 故障诊断:如何在日志中轻松定位大事务.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:教你快速定位加锁的 SQL.md.html">MySQL 故障诊断:教你快速定位加锁的 SQL.md.html</a>
</li>
<li>
<a href="/文章/MySQL 日志详解.md.html">MySQL 日志详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL 的半同步是什么?.md.html">MySQL 的半同步是什么?.md.html</a>
</li>
<li>
<a href="/文章/MySQL中的事务和MVCC.md.html">MySQL中的事务和MVCC.md.html</a>
</li>
<li>
<a class="current-tab" href="/文章/MySQL事务_事务隔离级别详解.md.html">MySQL事务_事务隔离级别详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL优化优化 select count().md.html">MySQL优化优化 select count().md.html</a>
</li>
<li>
<a href="/文章/MySQL共享锁、排他锁、悲观锁、乐观锁.md.html">MySQL共享锁、排他锁、悲观锁、乐观锁.md.html</a>
</li>
<li>
<a href="/文章/MySQL的MVCC多版本并发控制.md.html">MySQL的MVCC多版本并发控制.md.html</a>
</li>
<li>
<a href="/文章/QingStor 对象存储架构设计及最佳实践.md.html">QingStor 对象存储架构设计及最佳实践.md.html</a>
</li>
<li>
<a href="/文章/RocketMQ 面试题集锦.md.html">RocketMQ 面试题集锦.md.html</a>
</li>
<li>
<a href="/文章/SnowFlake 雪花算法生成分布式 ID.md.html">SnowFlake 雪花算法生成分布式 ID.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html">Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 教程:如何开发一个 starter.md.html">Spring Boot 教程:如何开发一个 starter.md.html</a>
</li>
<li>
<a href="/文章/Spring MVC 原理.md.html">Spring MVC 原理.md.html</a>
</li>
<li>
<a href="/文章/Spring MyBatis和Spring整合的奥秘.md.html">Spring MyBatis和Spring整合的奥秘.md.html</a>
</li>
<li>
<a href="/文章/Spring 帮助你更好的理解Spring循环依赖.md.html">Spring 帮助你更好的理解Spring循环依赖.md.html</a>
</li>
<li>
<a href="/文章/Spring 循环依赖及解决方式.md.html">Spring 循环依赖及解决方式.md.html</a>
</li>
<li>
<a href="/文章/Spring中眼花缭乱的BeanDefinition.md.html">Spring中眼花缭乱的BeanDefinition.md.html</a>
</li>
<li>
<a href="/文章/Vert.x 基础入门.md.html">Vert.x 基础入门.md.html</a>
</li>
<li>
<a href="/文章/eBay 的 Elasticsearch 性能调优实践.md.html">eBay 的 Elasticsearch 性能调优实践.md.html</a>
</li>
<li>
<a href="/文章/不可不说的Java“锁”事.md.html">不可不说的Java“锁”事.md.html</a>
</li>
<li>
<a href="/文章/互联网并发限流实战.md.html">互联网并发限流实战.md.html</a>
</li>
<li>
<a href="/文章/从ReentrantLock的实现看AQS的原理及应用.md.html">从ReentrantLock的实现看AQS的原理及应用.md.html</a>
</li>
<li>
<a href="/文章/从SpringCloud开始聊微服务架构.md.html">从SpringCloud开始聊微服务架构.md.html</a>
</li>
<li>
<a href="/文章/全面了解 JDK 线程池实现原理.md.html">全面了解 JDK 线程池实现原理.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性理论与算法.md.html">分布式一致性理论与算法.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性算法 Raft.md.html">分布式一致性算法 Raft.md.html</a>
</li>
<li>
<a href="/文章/分布式唯一 ID 解析.md.html">分布式唯一 ID 解析.md.html</a>
</li>
<li>
<a href="/文章/分布式链路追踪:集群管理设计.md.html">分布式链路追踪:集群管理设计.md.html</a>
</li>
<li>
<a href="/文章/动态代理种类及原理,你知道多少?.md.html">动态代理种类及原理,你知道多少?.md.html</a>
</li>
<li>
<a href="/文章/响应式架构与 RxJava 在有赞零售的实践.md.html">响应式架构与 RxJava 在有赞零售的实践.md.html</a>
</li>
<li>
<a href="/文章/大数据算法——布隆过滤器.md.html">大数据算法——布隆过滤器.md.html</a>
</li>
<li>
<a href="/文章/如何优雅地记录操作日志?.md.html">如何优雅地记录操作日志?.md.html</a>
</li>
<li>
<a href="/文章/如何设计一个亿级消息量的 IM 系统.md.html">如何设计一个亿级消息量的 IM 系统.md.html</a>
</li>
<li>
<a href="/文章/异步网络模型.md.html">异步网络模型.md.html</a>
</li>
<li>
<a href="/文章/当我们在讨论CQRS时我们在讨论些神马.md.html">当我们在讨论CQRS时我们在讨论些神马.md.html</a>
</li>
<li>
<a href="/文章/彻底理解 MySQL 的索引机制.md.html">彻底理解 MySQL 的索引机制.md.html</a>
</li>
<li>
<a href="/文章/最全的 116 道 Redis 面试题解答.md.html">最全的 116 道 Redis 面试题解答.md.html</a>
</li>
<li>
<a href="/文章/有赞权限系统(SAM).md.html">有赞权限系统(SAM).md.html</a>
</li>
<li>
<a href="/文章/有赞零售中台建设方法的探索与实践.md.html">有赞零售中台建设方法的探索与实践.md.html</a>
</li>
<li>
<a href="/文章/服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html">服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html</a>
</li>
<li>
<a href="/文章/深入浅出Cache.md.html">深入浅出Cache.md.html</a>
</li>
<li>
<a href="/文章/深入理解 MySQL 底层实现.md.html">深入理解 MySQL 底层实现.md.html</a>
</li>
<li>
<a href="/文章/漫画讲解 git rebase VS git merge.md.html">漫画讲解 git rebase VS git merge.md.html</a>
</li>
<li>
<a href="/文章/生成浏览器唯一稳定 ID 的探索.md.html">生成浏览器唯一稳定 ID 的探索.md.html</a>
</li>
<li>
<a href="/文章/缓存 如何保证缓存与数据库的双写一致性?.md.html">缓存 如何保证缓存与数据库的双写一致性?.md.html</a>
</li>
<li>
<a href="/文章/网易严选怎么做全链路监控的?.md.html">网易严选怎么做全链路监控的?.md.html</a>
</li>
<li>
<a href="/文章/美团万亿级 KV 存储架构与实践.md.html">美团万亿级 KV 存储架构与实践.md.html</a>
</li>
<li>
<a href="/文章/美团点评Kubernetes集群管理实践.md.html">美团点评Kubernetes集群管理实践.md.html</a>
</li>
<li>
<a href="/文章/美团百亿规模API网关服务Shepherd的设计与实现.md.html">美团百亿规模API网关服务Shepherd的设计与实现.md.html</a>
</li>
<li>
<a href="/文章/解读《阿里巴巴 Java 开发手册》背后的思考.md.html">解读《阿里巴巴 Java 开发手册》背后的思考.md.html</a>
</li>
<li>
<a href="/文章/认识 MySQL 和 Redis 的数据一致性问题.md.html">认识 MySQL 和 Redis 的数据一致性问题.md.html</a>
</li>
<li>
<a href="/文章/进阶Dockerfile 高阶使用指南及镜像优化.md.html">进阶Dockerfile 高阶使用指南及镜像优化.md.html</a>
</li>
<li>
<a href="/文章/铁总在用的高性能分布式缓存计算框架 Geode.md.html">铁总在用的高性能分布式缓存计算框架 Geode.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/面试最常被问的 Java 后端题.md.html">面试最常被问的 Java 后端题.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计在互联网业务开发中的实践.md.html">领域驱动设计在互联网业务开发中的实践.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计的菱形对称架构.md.html">领域驱动设计的菱形对称架构.md.html</a>
</li>
<li>
<a href="/文章/高效构建 Docker 镜像的最佳实践.md.html">高效构建 Docker 镜像的最佳实践.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>MySQL事务_事务隔离级别详解</h1>
<h2>使用事务语法</h2>
<blockquote>
<ol>
<li>开启事务start transaction可以简写为 begin</li>
<li>然后记录之后需要执行的一组sql</li>
<li>提交commit</li>
<li>如果所有的sql都执行成功则提交将sql的执行结果持久化到数据表内。</li>
<li>回滚rollback</li>
<li>如果存在失败的sql则需要回滚将sql的执行结果退回到事务开始之时</li>
<li>无论回滚还是提交,都会关闭事务!需要再次开启,才能使用。</li>
<li>还有一点需要注意,就是事务只针对当前连接。</li>
</ol>
</blockquote>
<p><strong>下面我们来进行演示:</strong></p>
<blockquote>
<p>使用第一个链接A开启事务后执行一条update语句。
结果成功,数据已经变成修改之后!</p>
<p><img src="assets/20151216202855634" alt="这里写图片描述" /></p>
<p>此时我们没有提交。
再从其他连接B来查看发现数据末更改</p>
<p><img src="assets/20151216203147520" alt="这里写图片描述" /></p>
<p>此时如果连接A选择提交<strong>也就是commit操作。则连接B的数据也会发生变化。</strong></p>
<p>而如果连接A选择回滚<strong>也就是rollback操作。则连接A再次查询则发现数据还原。</strong></p>
</blockquote>
<hr />
<h2>基本原理</h2>
<blockquote>
<p>语法说完了,浮躁的人也不用继续看下去了。下面简单说一下事务的基本原理吧。
<strong>提交,就会将结果持久化,不提交就不会。</strong></p>
<p>如果我们不开启事务只执行一条sql马上就会持久化数据可以看出<strong>普通的执行就是立即提交。这是因为MySQL默认对sql语句的执行是自动提交的。</strong></p>
<p><strong>也就是说开启事务实际上就是关闭了自动提交的功能改成了commit手动提交</strong></p>
<p>我们可以通过简单的对是否自动提交加以设置,完成开启事务的目的!
自动提交的特征是保存在服务的一个autocommit的变量内。可以进行修改</p>
<blockquote>
<p><strong>set autocommit = 0关闭</strong></p>
<p>set autocommit = 1开启</p>
</blockquote>
<p>还需要注意一点就是事务类似于外键约束只被innodb引擎支持。</p>
</blockquote>
<hr />
<h2>特点</h2>
<blockquote>
<p>下面来说说事务的特点ACID。也就是原子性一致性隔离性和持久性。</p>
<p>**原子性:**事务的一组操作是原子的不可再分割的这组操作要么同时完成要么同时不完成。类似于一个CAScompare and swap有时间会讲解cas</p>
<p>**一致性:**事务在执行前后数据的完整性保持不变。(例:原本的外键约束在进行事务成功后不会损坏)</p>
<p>**隔离:**当多个事务同时操作一个<a href="http://lib.csdn.net/base/mysql">数据库</a>时,可能存在并发问题,此时应保证各个事务要进行隔离,事务之间不能互相干扰。</p>
<p>**持久性:**事务一旦被提交,就不可能再被回滚!</p>
</blockquote>
<hr />
<h2>事务并发</h2>
<p>事务并发会带来一些问题,所以才有了不同的事务隔离级别。要想了解事务的隔离级别,就必须首先了解事务并发会带来的问题。
一般来说,会出现三类数据读问题和数据更新问题。</p>
<h3>脏读</h3>
<p>一个事务正在对一条记录做修改,但未提交,另一个事务读取了这些脏数据,并进一步处理,就会产生未提交的数据依赖。
举一个例子:</p>
<table>
<thead>
<tr>
<th align="left">时间</th>
<th align="left">转账事务A</th>
<th align="left">取款事务B</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">T1</td>
<td align="left"></td>
<td align="left">开始事务</td>
</tr>
<tr>
<td align="left">T2</td>
<td align="left">开始事务</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T3</td>
<td align="left"></td>
<td align="left">查询账户余额为1000元</td>
</tr>
<tr>
<td align="left">T4</td>
<td align="left"></td>
<td align="left">取出500元把余额改为500元</td>
</tr>
<tr>
<td align="left">T5</td>
<td align="left">查询账户余额为500元脏读</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T6</td>
<td align="left"></td>
<td align="left">撤销事务余额恢复为1000元</td>
</tr>
<tr>
<td align="left">T7</td>
<td align="left">汇入100元把余额改为600元</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T8</td>
<td align="left">提交事务</td>
<td align="left"></td>
</tr>
</tbody>
</table>
<p>A读取了B尚未提交的脏数导致最后余额为600元。</p>
<h3></h3>
<h3>不可重复读</h3>
<p>一个事务在不同时间读取数据不一致。
举一个例子:</p>
<table>
<thead>
<tr>
<th align="left">时间</th>
<th align="left">取款事务A</th>
<th align="left">转账事务B</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">T1</td>
<td align="left"></td>
<td align="left">开始事务</td>
</tr>
<tr>
<td align="left">T2</td>
<td align="left">开始事务</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T3</td>
<td align="left"></td>
<td align="left">查询账户余额为1000元</td>
</tr>
<tr>
<td align="left">T4</td>
<td align="left">查询账户余额为1000元</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T5</td>
<td align="left"></td>
<td align="left">取出100元把余额改为900元</td>
</tr>
<tr>
<td align="left">T6</td>
<td align="left"></td>
<td align="left">提交事务</td>
</tr>
<tr>
<td align="left">T7</td>
<td align="left">查询账户余额为900元和T4读取的不一致</td>
<td align="left"></td>
</tr>
</tbody>
</table>
<p>可以看到最后读取的数据不一致。</p>
<h3>幻读</h3>
<p>幻读和不可重复读的概念类似,都是不同时间数据不一致,只不过幻读是针对新增数据,而不可重复读是针对更改数据。
看一个例子:</p>
<table>
<thead>
<tr>
<th align="left">时间</th>
<th align="left">统计金额事务A</th>
<th align="left">转账事务B</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">T1</td>
<td align="left"></td>
<td align="left">开始事务</td>
</tr>
<tr>
<td align="left">T2</td>
<td align="left">开始事务</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T3</td>
<td align="left">查询用户id为8的数据结果为空执行插入id为pk</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">T4</td>
<td align="left"></td>
<td align="left">新增一个id为8的数据</td>
</tr>
<tr>
<td align="left">T5</td>
<td align="left"></td>
<td align="left">提交事务</td>
</tr>
<tr>
<td align="left">T6</td>
<td align="left">提交事务,插入报错</td>
<td align="left"></td>
</tr>
</tbody>
</table>
<hr />
<h2>隔离级别</h2>
<p>事务并发带来的问题前文已经描述得非常仔细了。事务的隔离级别就是为了针对并发出现的问题,不同的级别可以保证不同的一致性。</p>
<p>为了解决上面讲到的并发事务处理带来的问题SQL标准提出了<strong>4个等级的事务隔离级别</strong>。不同的隔离级别在同样的环境下会出现不同的结果。</p>
<p><strong>隔离级别设置及查看</strong></p>
<blockquote>
<p><strong>mysql&gt; select @@tx_isolation;</strong>
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)</p>
<p><strong>mysql&gt; set tx_isolation = 0; (备注0 - 3 对应数据库四种隔离级别)</strong>
Query OK, 0 rows affected (0.00 sec)</p>
</blockquote>
<p><strong>下面看看四种隔离级别的比较:</strong></p>
<blockquote>
<p>Read Uncommitted读取未提交内容</p>
<p>在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。<strong>读取未提交的数据也被称之为脏读Dirty Read</strong></p>
<p>Read Committed读取提交内容</p>
<p>这是大多数数据库系统的默认隔离级别但不是MySQL默认的。它满足了隔离的简单定义一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读Nonrepeatable Read<strong>因为同一事务的其他实例在该实例处理其间可能会有新的commit所以同一select可能返回不同结果。</strong></p>
<p>Repeatable Read可重读</p>
<p>这是MySQL的默认事务隔离级别它确保同一事务的多个实例在并发读取数据时会看到同样的数据行。不过理论上这会导致另一个棘手的问题幻读Phantom Read<strong>简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影”行</strong>。InnoDB和Falcon存储引擎通过多版本并发控制MVCCMultiversion Concurrency Control机制解决了该问题。</p>
<p>Serializable可串行化
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,<strong>它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。</strong></p>
</blockquote>
<table>
<thead>
<tr>
<th align="left">隔离级别</th>
<th align="left">读数据一致性</th>
<th align="left">脏读</th>
<th align="left">不可重复读</th>
<th align="left">幻读</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">未提交读Read uncommitted</td>
<td align="left">最低级别,只能保证不读取物理上损坏的数据</td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">已提交读Read committed</td>
<td align="left">语句级</td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">可重复读Repeatable read</td>
<td align="left">事务级</td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">可序列化Serializable</td>
<td align="left">最高级别,事务级</td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div>
<div style="float: left">
<a href="/文章/MySQL中的事务和MVCC.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/文章/MySQL优化优化 select count().md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709980093a538b66","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>