文章目录
- 认识事务的隔离性
- 具体认识四种隔离级别
-
- 1.读未提交【Read Uncommitted】
- 2.读提交【Read Committed】
- 3.可重复读 【Repeatable Read】
- 4.串行化【serializable】
- 不同的隔离级别的安全问题
- 事务的一致性
认识事务的隔离性
认识事务的隔离级别
如何理解事务的原子性?
一个事务中可以有多条sql语句,也就是说一条事务可能会对数据库做很多操作。而事务的原子性指的就是,一条事务内的多条sql语句是同生共死的,他们要么一起执行,要么都不会被执行,不会出现事务结束之后一些语句执行成功,另外一些执行失败的情况。如果这个事务的某条操作执行过程中遇到了点问题,没法顺利完成,那其余的操作也不会执行,mysql会把数据库恢复到事务开始之前的状态
一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。事物执行中出现问题,执行不下去了,就立即回滚到执行前。
事务的隔离级别有哪些?
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Repeatable Read)
- 串行化(Serializable)
为什么要划分四种隔离级别?
隔离级别存在的意义是什么?为什么要划分出来这些隔离级别?如果是要解决多请求并发问题,那我给线程访问临界资源的动作上锁不就行了吗?
引入隔离级别最大的原因在于,mysql不仅想解决多请求并发处理问题,实现多线程对数据库的安全访问,还想在保证安全性的基础上,最大程度地提高执行效率(mysql想既要还要)。
四种隔离级别对安全性和执行效率做的平衡是不一样的。比如串行化,它是最安全的,但是执行效率是最慢的,读未提交(Read Uncommitted)是最不安全的,但是执行效率是最快的。如果单单是为了解决多请求并发处理的安全问题,那确实简单,直接上锁(对应串行化)就行了。但是在具体的场景中,可能有些场景不容易出现安全性的问题,不需要你给他提供那么严格的安全性保障,那我们就可以更弱一些的隔离级别,牺牲一部分安全性,从而为mysql运行换来更高的性能。
前面说的加锁,确实可以解决并发带来的数据不一致问题,但也是有缺点的,缺点是,你这种方式就让多线程访问临界资源时完全丧失了并发性。转化成了多线程串行执行,会导致各个线程的执行效率大大降低,这会直接影响到我们对数据库增删查改操作的执行效率
mysql对上述效率是很看重的,他想在确保安全性的基础上,尽可能提高进程执行的效率,于是就给隔离的程度划分了等级
像你刚刚说的那种方案,就是隔离等级的第四级,也就是最高级别的隔离,除此之外还有较低级别的三种隔离等级,等级越低的隔离越不安全,但效率越高。相当于用安全性去换效率
如何查看隔离级别?
隔离级别在宏观上又分为全局事务隔离级别和会话事务隔离级别,这俩含义也是不一样的
MSYQL中的会话是什么
一个MYSQL的会话 对应 一个客户端与MYSQL服务器之间建立起来的一个链接。连接是会话的 “物理载体”,一个连接对应一个会话,无论发起连接的客户端是否相同(比如是同一台电脑的 Navicat、同一程序的不同线程),只要是两次独立的连接请求(即建立了两条独立的 TCP 通信链路),MySQL 服务器就会为每一次连接分配独立的 “会话资源”
全局事务隔离级别和会话事务隔离级别有啥区别?
全局的可以管所有会话,当你修改了全局事务隔离级别之后,后面创建的新会话事务,其默认隔离级别就是你新改的全局事务隔离级别
会话事务隔离级别就管着这一个事务,当你修改了会话事务隔离级别之后,当前这个事务的隔离级别会变成你修改的那个值,但是后续新创建的事务隔离级别仍然由全局的隔离级别决定
如何查看当前全局事务的隔离级别?
select @@global.tx_isolation;
其中@@ 是用于引用系统变量的符号。也就是说tx_isolation是一个系统变量
如何查看当前会话事务的隔离级别?
select @@session.tx_isolation;
或者我们也可以直接输入select @@tx_isolation;它表示的也是当前会话事务的隔离级别
如何更改/设置隔离级别
如何更改/设置全局事务隔离级别?设置全局事务隔离级别有啥作用?
SET GLOBAL TRANSACTION ISOLATION LEVEL + 具体的隔离级别;
其中具体的隔离级别是我们前面说过的那四种中的一种
- READ - UNCOMMITTED读未提交
- READ - COMMITTED(读已提交)
- REPEATABLE - READ(可重复读)
- SERIALIZABLE(串行化)
比如SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
执行这条语句之后,后面MYSQL创建出的新会话的隔离级别默认都是READ COMMITTED(执行该语句的当前会话的隔离级别不受影响)
如何设置当前会话的事务隔离级别?
SET SESSION TRANSACTION ISOLATION LEVEL + 具体的隔离级别;
比如 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
这条语句执行之后,当前会话后面创建的新事务,隔离级别都是 READ COMMITTED。
但是如果当前会话结束了,假如说当前全局隔离级别设置的是REPEATABLE - READ(可重复读),那下次我创建一个新会话,该会话的默认事务隔离级别就不是 READ COMMITTED了,而是REPEATABLE - READ(可重复读)
一个已经开始的事务,其隔离级别还能改吗?
在 MySQL 中,一个已经开始的事务(活跃事务),其隔离级别无法被修改。一旦事务通过 START TRANSACTION(或隐式开启,如 autocommit=0 时的第一条 SQL)启动,它的隔离级别就被固定了,后续即使执行 SET TRANSACTION 或 SET SESSION TRANSACTION 语句,也不会影响这个正在进行的事务。
隔离级别修改指令的生效范围
输入上面更改隔离级别的指令之后,隔离级别会立即生效吗?当前还没提交的事务受不受影响?
执行SET GLOBAL TRANSACTION ISOLATION LEVEL + 具体的隔离级别;后,全局隔离级别会立即更新,但并不会对当前已有的会话产生影响。
执行SET SESSION TRANSACTION ISOLATION LEVEL + 具体的隔离级别;后,当前会话的事务隔离级别会立即更新,但并不会对当前会话正在进行中的事务产生影响
假如说当前会话隔离级别设置的是REPEATABLE - READ(可重复读),然后我在当前会话中执行SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;,将全局隔离级别设置READ COMMITTED,那请问当前会话创建的下一条事务,他的隔离级别是什么呢?
是当前会话的隔离级别REPEATABLE - READ(可重复读)。因为全局隔离级别的设置语句并不会改变当前会话的隔离级别
假如说当前会话隔离级别设置的是REPEATABLE - READ(可重复读),然后我在当前会话中执行SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;,将当前会话的隔离级别修改为READ COMMITTED,那请问当前会话创建的下一条事务,他的隔离级别是什么呢?
是当前会话修改之后的隔离级别READ COMMITTED
假如说当前会话隔离级别设置的是REPEATABLE - READ(可重复读),在当前会话中我创建了一个事务还没提交,这时候我在当前会话中执行SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;,将当前会话的隔离级别修改为READ COMMITTED,那么请问还没提交的那个事务,它的隔离级别是什么呢?
是REPEATABLE - READ(可重复读),该事务的隔离级别 以 当前会话创建该事务时的隔离级别 为准
登出再登录对隔离级别的影响
当你登出当前会话并重新登录后,服务器就会为当前的新链接创建一个新的会话。新的会话默认采用最新设置的全局隔离级别
假如说当前会话隔离级别设置的是REPEATABLE - READ(可重复读),然后我在当前会话中执行SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;,将全局隔离级别设置READ COMMITTED,然后我直接退出当前会话重新登录。进入新会话时,这个新会话的事务隔离级别就是READ COMMITTED了
具体认识四种隔离级别
1.读未提交【Read Uncommitted】
如何理解读未提交?
意思就是在这种隔离级别下,mysql允许其他事务查看一个事务未提交时的数据。这种隔离级别没有任何隔离性,效率最高。
既然他效率最高,那他安全性肯定是最低的。我现在就想问
读未提交的隔离性下存在哪些安全问题呢?
- 脏读问题
- 不可重复读问题
- 幻读问题
什么是脏读问题 ?
幻读和不可重复读问题我们后面在说,现在我们重点来认识一下脏读
首先我们来认识一下脏读操作,所谓的脏读操作指的是:一个事务读取到了另一个事务未提交的数据
脏读问题指的就是脏读操作带来的问题,即若一个事务读取了另一个事务未提交的数据,但另一个事务后续未提交,直接回滚了,那么先读取的事务拿到的数据就是无效的,基于该数据的操作也可能出错。
比如,银行转账时,事务 A 从账户 A 扣钱但未提交,事务 B 此时读取账户 A 余额,若事务 A 回滚,事务 B 读到的就是错误余额 。
2.读提交【Read Committed】
读提交是什么意思?
意思就是在这种隔离级别下,mysql允许其他事务查看一个事务提交之后更新的数据,但是不允许其他事物查看一个事务未提交时更新的数据
提交之前看不到,提交之后就能看到了
读提交的隔离性下,解决了哪些安全问题?还存在哪些安全问题?
-
读提交的隔离性下,已经不存在脏读问题了(为什么?)
因为在读提交的隔离性下,不允许在一个事务内部查看其他未提交事务的数据 -
但是仍然存在下面两种问题:
不可重复读问题(什么是不可重复读问题?)
幻读问题(什么是幻读问题?)
你可以这么认为,设置读提交的隔离级别,主要就是为了解决脏读问题的,就是不允许其他的事务去读取一个未提交事务更新的数据。一个事务提交之前,他对数据库做的任何更新操作都不允许被其他事务看见。
3.可重复读 【Repeatable Read】
可重复读是什么意思?
什么是不可重复读?
想要理解可重复读,我们可以先理解一下什么叫做不可重复读
注意看这张图的右侧,同一个事务内,同样的读取,在不同的时间段(依旧还在事务操作中!),读取到了不同的值,这种现象叫做不可重复读(non reapeatable read)!!

不可重复读这个概念感觉和幂等这个概念挺像的。所谓幂等指的就是多次执行相同的操作,最终得到的结果与执行一次完全一致。在上图中右端客户端执行了两次相同的查询。操作但是得到的结果却是不同的。那么我们就称此时这个操作就是不幂等的。
什么是可重复读
那可重复读就是指:一个事务,在这个事务的生命周期内的任意时间读取数据库中的数据,得到的结果始终是相同的
可重复读在上一个隔离级别读已提交的基础上,又做了哪些限制?
上一个隔离级别读已提交,不允许其他事务读取一个没有提交的事务中更新的数据。但是如果一个事物已经提交了,此时其他运行中的事务就可以同步到数据库更新之后的新数据了。
可重复读继承了读已提交的约束,不允许事务在运行过程中查看未提交事务更新的数据,在这个基础上又做了进一步的限制:事务是看不到其运行过程中数据库的更新操作的。即一个事务在执行过程中,不允许查看在该事务运行过程中提交的事务的更新数据,该事务在运行过程中看到的,是该事务开始时的老数据库(数据库在该事务启动时的快照)
为什么要引入可重复读这个隔离级别?
原因就在于,上一个级别:读提交,存在着一个不可重复读的问题。可重复读这个隔离级别,就是为了解决不可重复读问题而设置的。那什么是不可重复读问题呢?
什么是不可重复读问题?
现在我有一个场景,公司年终的时候根据每个员工的业绩给员工颁奖,奖品的发放规则如下:
- 将所有贡献值在300到500之间的员工名单筛选出来,给他们每个人发一个台灯
- 将所有贡献值在500到800之间的员工名单筛选出来,给他们每个人发一个键盘
- 将所有贡献值在800到2000之间的员工名单筛选出来,给他们每个人发一个手机
- 将所有贡献值在2000以上的员工名单筛选出来,给他们每个人发一个电脑
在公司内部数据库处理这个奖品发放的业务中,我们需要先把每个奖品对应的员工给分好,然后发奖。对应的事务可能是:
mysql> begin

最低0.47元/天 解锁文章
&spm=1001.2101.3001.5002&articleId=151116439&d=1&t=3&u=0490bceb070049e083c9bab5b416ba5f)
2175

被折叠的 条评论
为什么被折叠?



