mysql——事务(下)

事务隔离级别

如何理解隔离性?

MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行

一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题,可以随时回滚。所以单个事务,对用户表现出来的特性,就是原子性。

但,毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会 出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。

就如同你妈妈给你说:你要么别学,要学就学到最好。至于你怎么学,中间有什么困难,你妈妈不关心。那么你的学习,对你妈妈来讲,就是原子的。那么你学习过程中,很容易受别人干扰,此时,就需要将你的学习隔离开,保证你的学习环境是健康的。

数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性

数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

隔离级别的分类

读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。

读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。

可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行 中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。

串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突, 从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争 (这种隔离级别太极端,实际生产基本不使用)

查看隔离性

查看全局隔离级别

注:在mysql8之前是select @@gloal.tx_isolation;之后的版本是我们图中显示的。

查看会话(当前)全局隔离级别

默认隔离级别同session

设置隔离性

设置当前会话隔离级别/全局隔离级别语法

set [session | global] transaction isolation level {read uncommitted | read committed | repeatable read | serializable}

我们在这里修改了当前会话的隔离级别(默认也会修改),发现并不影响其他另起会话,但如果我们要修改全局性隔离,那么其他会话也会跟着修改,我们每次启动服务器初始化的隔离级别就是用全局的隔离级别进行初始化。

各个隔离性的效果

读未提交------read uncommitted

可以发现,两个客户端都已经开始进行了事务,我们说过,要保持事务的原子性,那么一个事务整个过程做完,另一个事务才能看到。但是图中我们还没有进行commit另一端已经收到了修改,这就是读未提交的效果(名副其实,能读到未提交的内容,也叫脏读)

该模式几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用

读提交------read committed

这里和上面的区别是,左边终端在commit之前,无论如何修改,另一端都查不到数据。只有左边的commit了,右边才能知道数据被修改了。这就是读提交(可以读到提交的内容)。

但是这也并不符合事务的原子性,因为在这个场景中,我们要确保两边的事务开始到结束期间都不能接受到任何数据变化,然而左边貌似满足要求,但右边明显不满足(因为我右边没有commit也仍然收到了数据更新)

如果在此期间我们右表开始有数据,在查询事务的过程中突然发现了新增的数据(就会造成不好的结果,我们并不期望有新结果插入)。

那么就造成了,同一个事务内,同样的读取,在不同的时间段 (依旧还在事务操作中!),读取到了不同的值,这种现象叫做不可重复读(non reapeatable read)!!

可重复读------repeatable read

我们首先全部启动事务,左边插入两个数据,此时右边select并没有数据,当左边commit后,右边select仍查不到数据,当右边也commit后再select就可以查到数据了。

在右边终端中,事务无论什么时候进行查找,看到的结果都是一致的,这叫做可重复读!

但是,一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据(因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题),会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读 (phantom read)。很明显,MySQL在RR级别的时候,是解决了幻读问题的。(RR是mysql默认的)

串行化------serializable

我们先让右边终端begin,开始时候先让右边插入一个数据,结果左边在select的时候居然卡住了,过了一会报错timeout超时,包括我们在左边插入数据也不可以。当我们右边的SQLcommit后,才发现左边的可以正常输入使用。因此,这种模式是加了锁的!只有一边结束事务其他终端才可以接着访问。(其他终端访问时会把请求放入等待队列中,如果长时间不退出就会超时)

总结四大模式

其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。

不可重复读的重点是修改和删除:同样的条件, 你读取过的数据,再次读取出来发现值不一样了

幻读的重点在于新增:同样的条件, 第1次和第2次读出来的记录数不一样,说明: mysql 默认的隔离级别是可重复读,一般情况下不要修改

上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大。

一致性

事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务 成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中 断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一 致)的状态。因此一致性是通过原子性来保证的。

其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是,一致性,是由用户决定的。 而技术上,通过AID保证C

相关推荐
likangbinlxa16 分钟前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k44 分钟前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫2 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i3 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.3 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn3 小时前
【Redis】渐进式遍历
数据库·redis·缓存