MySQL 脏读 幻读 不可重复读 加锁读 丢失修改 解释

事务的ACID特性

原子性(atomicity)

原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。

一致性(consistency)

执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;

隔离型(isolation)

事务的隔离性是指一个事务的执行 不能被其他事务干扰 ,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的 ,接下来的其他操作和数据库故障不应该对其有任何影响。

持久性是通过 事务日志 来保证的。日志包括了 重做日志 和 回滚日志 。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。

事务的隔离级别

MySQL InnoDB 存储引擎的默认⽀持的隔离级别是 REPEATABLE-READ(可重读)
我们可以通过 5.7.20版本之 前 使用 SELECT @@tx_isolation; 命令来查看
我们可以通过 5.7.20版本之 后 使用 SELECT @@TRANSACTION_isolation; 命令来查看

READ UNCOMMITTED:读未提交

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。

READ COMMITTED:读已提交

它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。

REPEATABLE READ:可重复读

事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别。

SERIALIZABLE:可串行化

确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。

隔离级别脏读不可重读幻读加锁读
READ UNCOMMITTED(读未提交) YESYESYESNO
READ COMMITTED (读已提交)NOYESYESNO
REPEATABLE READ(可重复读)NONOYESNO
SERIALIZABLE (可串行化 / 序列化)NONONOYES
脏读(Dirty read)

当⼀个事务正在访问数据并且对数据进⾏了修改,⽽这种修改还没有提交到数据库中,这时另外⼀个事务也访问了这个数据,然后使⽤了这个数据。因为这个数据是还没有提交的数据,那么另外⼀个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

幻读(Phantom read)

幻读与不可重复读类似。它发⽣在⼀个事务(T1)读取了⼏⾏数据,接着另⼀个并发事务(T2)插⼊了⼀些数据时。在随后的查询中,第⼀个事务(T1)就会发现多了⼀些原本不存在的记录,就好像发⽣了幻觉⼀样,所以称为幻读。

不可重复读(Unrepeatableread)

指在⼀个事务内多次读同⼀数据。在这个事务还没有结束时,另⼀个事务也访问该数据。那么,在第⼀个事务中的两次读数据之间,由于第⼆个事务的修改导致第⼀个事务两次读取的数据可能不太⼀样。这就发⽣了在⼀个事务内两次读到的数据是不⼀样的情况,因此称为不可重复读。

加锁读(Locking Reads)

在同一个事务中,如果你先查询数据,随后对相关数据进行插入或修改,那么在标准的SLELECT中不会给出足够的保护。在你查询期间另一个事务可以更新或者删除相同的行。InnoDB提供两种类型的加锁读

  • SELECT … LOCK IN SHARE MODE
    给读到的每一行都加共享锁。其它的会话也可以读到这些行,但是它们不能修改这些行,直到你的事务提交。如果这些行被其它事务修改了但尚未提交,你的 查询必须等待直到那个事务结束。

  • SELECT … FOR UPDATE
    对于检索到的没一个索引记录,锁定这些行和与之关联的索引记录

其实,前者是加意向共享锁,后者加意向排它锁。

丢失修改(Lost to modify)

指在⼀个事务读取⼀个数据时,另外⼀个事务也访问了该数据,那么在第⼀个事务中修改了这个数据后,第⼆个事务也修改了这个数据。这样第⼀个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

不可重复读和幻读区别

不可重复读的重点是修改⽐如多次读取⼀条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除⽐如多次读取⼀条记录发现记录增多或减少了。

解决办法

以上出现的都是数据库事务隔离级别的问题

修改MySQL的事务隔离级别,修改服务器配置文件

# 修改配置文件
cd /etc/mysql/mysql.conf.d/
vim mysqld.cnf

# 添加以下代码
transaction-isolation=READ-COMMITTED

在Oracle,SqlServer中都是选择读已提交(Read Commited)作为默认的隔离级别,而Mysql却选择可重复读(Repeatable Read)作为默认隔离级别

MySQL不同场景命令行清屏的方式

  • powershell使用mysql.exe

    • 在这种情况下,需要mysql.exe版本是8.0及以上的,它可以调用系统命令,所以直接使用system cls就可以实现清屏。
  • Windows下使用mysql-shell

    • 这个就如同大多数shell一样,使用快捷键Ctrl + L可以实现清屏。
  • navicat中使用命令列工具

    • 可以在界面上部的查看中有清屏按钮,但是这对于程序员来说太麻烦,在命令列里面使用clear命令可以实现清屏。
  • mycli和linux下的mysql命令行

    • 这些仿shell的工具其实都可以使用Ctrl + L实现清屏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值