MySQL的事务学习。事务的四大特性。事务的提交和回滚。简单说一下MySQL是怎么解决幻读这个问题的。

目录

事务的四大特性

(1)原子性(Atomicity)

(2)一致性(Consistency)

(3)隔离性(Isolation)

(4)持久性(Durability)

事务提交、回滚

事务特性--隔离性

4.2 读未提交

4.3 读已提交

4.4 可重复读

4.5 串行化

MVCC,多版本并发控制


在讨论这个问题之前我们要先了解事务的一些基本知识:

(1)在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务

(2)事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行

(3)事务用来管理 insert,update,delete 语句。

事务的四大特性

一般来说,事务是必须满足4个条件(ACID):

(1)原子性(Atomicity)

一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

(2)一致性(Consistency)

        在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。(比如:A向B转账,不可能A扣了钱,B却没有收到,总的钱数是要不变的)

(3)隔离性(Isolation)

        数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

(4)持久性(Durability)

事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

事务提交、回滚

1、事务是指准备要做的或者是正在做的事情,没有commit的事务操作,对数据的修改是不会被同步到磁盘中的;

2、提交事务:事务提交成功后,会将操作数据的SQL语句(insert、update、delete)的结果和硬盘中的数据进行一次同步;

3、事务回滚:将所有的SQL操作(插入,更新,删除)语句的操作历史记录清空,把数据恢复到事务开始前的状态;简单来说就是当一个事务的某一个操作发生问题时,整个事务可以回滚掉,就像没有做任何操作一样,数据又回到了事务开始前的状态。

当开启事务之后,所有对数据的操作都会被存储在事务日志中,而只有当我们进行提交事务的操作后,才会将我们操作的数据的结果同步到数据库表中。
 

事务特性--隔离性

(1)读未提交:read uncommitted 可以理解为有人在处理数据,但是还没有提交(commit),但是此时却有人在读取别人操作的数据,此时就会产生脏读,因为操作的数据可能会被回滚;这一级是最低的隔离级别;

(2)读已提交:read committed 可以解决脏读,但是解决不了不可重复读;不可重复读是一种现象;

(3)可重复读:repeatable read 幻读是一种现象,针对的是insert和delete的SQL语句;

(4)串行化:serializable

脏读不可重复读幻读
Read uncommitted
Read committed×
Repeatable read××
Serializable×××

不可重复读:A事务在本次事务中,对自己操作过的数据,进行了【多次读取发现数据不一致】,不可重复读;

幻读:可以理解为这是一种现象,就是查询的时候出现了数据不一致都可以称为幻读;

可重复读:A事务在本次事务中,对未操作的数据进行多次查询,发现第一次没有,第二次出现了就像幻觉一样。或者第一次【有】而第二次【没有】;

查看个设置事务的隔离级别:

SELECT @@global.tx_isolation, @@tx_isolation;
​
set session transaction isolation level repeatable read;
​
SET  transaction isolation level read uncommitted;
SET  transaction isolation level read committed;
set  transaction isolation level repeatable read;
SET  transaction isolation level serializable;
​
SET GLOBAL transaction isolation level read uncommitted;
SET GLOBAL transaction isolation level read committed;
set GLOBAL transaction isolation level repeatable read;
SET GLOBAL transaction isolation level serializable;
​
其中,SESSION 和 GLOBAL 关键字用来指定修改的事务隔离级别的范围:
SESSION:表示修改的事务隔离级别将应用于当前 session(当前 cmd 窗口)内的所有事务;
GLOBAL:表示修改的事务隔离级别将应用于所有 session(全局)中的所有事务,且当前已经存在的 session 不受影响;
如果省略 SESSION 和 GLOBAL,表示修改的事务隔离级别将应用于当前 session 内的下一个还未开始的事务。

4.2 读未提交

  • 事物A和事物B,事物A未提交的数据,事物B可以读取到

  • 这里读取到的数据叫做“脏数据”,叫脏读

  • 这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别

简而言之第一个事务没提交,别的事物就能读,这种数据不一定是正确的因为人家可能回滚呀!

案例:

楠哥发工资了,老婆让楠哥把工资打到他老婆的账号上,但是该事务并未提交,就让老婆去查看,老婆一看真的打了钱了,高高兴兴关了网页,此时楠哥急中生智进行回滚,钱瞬间回来,一次蒙混了一个月工资。所以楠哥老婆看到的数据我们称之为“脏数据”。

出现上述情况,即我们所说的脏读 ,两个并发的事务,“事务A:领导给singo发工资”、“事务B:singo查询工资账户”,事务B读取了事务A尚未提交的数据。

4.3 读已提交

能读到别的事物已经提交的数据。

A事务在本次事务中,对自己操作过的数据,进行了【多次读取发现数据不一致】,不可重复读

简单点说就是不能让我好好的重复读,一个事务里读出来的数据都不一样,让不让人干活了。

针对的语句update和delete,会导致不可重复读

楠哥拿着工资卡去消费,系统读取到卡里确实有10200元,而此时她的老婆也正好在网上转账,把楠哥工资卡的2000元转到另一账户,并在 楠哥之前提交了事务,当楠哥扣款时,系统检查到楠哥的工资卡和上次读取的不一样了,楠哥十分纳闷,明明卡里有钱,为何......

当隔离级别设置为Read committed 时,避免了脏读,但是可能会造成不可重复读。

大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。如何解决不可重复读这一问题,请看下一个隔离级别。

4.4 可重复读

A事务在本次事务中对未操作的数据进行多次查询,发现第一次没有,第二次出现了就像幻觉一样。或者第一次【有】而第二次【没有】。针对delete和insert。 MySQL使用了mvcc里面的【快照读】解决来拿这个问题;

案例

楠哥的老婆在银行部门工作,她时常通过银行内部系统查看楠哥的账户信息。有一天,她正在查询到楠哥账户信息时发现楠哥只有一个账户,心想这家伙应该没有私房钱。此时楠哥在另外一家分行右开了一个账户,准备存私房钱。一次同时楠哥老婆点击了打印,结果打印出的楠哥账户居然多了一个,真实奇怪。

MySQL 通过多版本并发控制(MVCC)(快照读/一致性读)其实解决了幻读问题。

原理:事务开启后,将历史数据存一份快照,其他事务增加与删除的数据,对于当前事务来说是不可见的。

4.5 串行化

  • 事务A和事务B,事务A在操作数据库时,事务B只能排队等待

  • 这种隔离级别很少使用,吞吐量太低,用户体验差

  • 这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发。

  • 别的地方一用这个数据就不能修改删除,直到别的地方提交

 

MVCC,多版本并发控制

简单了解一下:

MVCC(多版本并发控制 )就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现;

像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁;

像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;

MVCC多版本并发控制指的是 “维持一个数据的多个版本,使得读写操作没有冲突,而在MySQL中,实现这么一个MVCC理想概念,我们就需要MySQL提供具体的功能去实现它,而快照读就是MySQL为我们实现MVCC理想模型的其中一个具体非阻塞读功能。而相对而言,当前读就是悲观锁的具体功能实现;

要说的再细致一些,快照读本身也是一个抽象概念,再深入研究。MVCC模型在MySQL中的具体实现则是由  3个隐式字段undo日志Read View 等去完成,这里就不再赘述,有兴趣的小伙伴们可以自行去了解;

不加锁的select操作就是快照读,即不加锁的非阻塞;

【笔记是基于学习 楠哥 的MySQL课程。】

如果有不对的或者是误导人的地方,请各位大佬谅解和指教,本人一定虚心学习。谢谢^_^

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值