浅尝辄止下MySQL事务

本文详细介绍了事务的原子性、一致性、隔离性和持久性,以及MySQL中redo_log和undo_log的区别,同时讨论了事务带来的问题如脏读、修改丢失等,并剖析了不同事务隔离级别的工作原理。
摘要由CSDN通过智能技术生成

事务的四大特性

谈起事务,自然是事务的四大特征

原子性

事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。

一致性

指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。

隔离性

多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。

持久性

表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。

MySQL的3大文件

MySQL事务的处理,我们就需要知道3个文件bin_log,redo_log,undo_log。

下面我们主要以innodb为例介绍,innodb的内存结构如下

我们简单理解undo_log和redo_log区别:

事务提交崩溃,通过 undo_log 回滚事务
事务提交崩溃,通过 redo_log 恢复事务

redo_log

可以简单的理解他是重做日志。让事务具备持久性。他的操作步骤为:

1.事务首先会把数据页的数据放入缓冲池。

2.修改信息后,缓冲池中的数据就为脏页,将操作记录到redo_log_buffer中。

3.当commit(提交数据)时候redo_log_buffer刷到redo_log文件中,让脏页的数据具备持久化。可以在配置信息中配置刷盘频率,刷盘规则等。

4.redo_log文件在事务提交时,进行一次性刷盘,存入数据页中。

这里有个问题,为啥不直接把脏页数据刷盘到磁盘中呢?中间还要通过redo_log_buffer写到redo_log文件中,这样就绕了一圈才存储的,为什么呢?

其实这脏页数据是随机存储的,而redo_log是顺序存储的,顺序存储的执行效率要高很多。

undo_log

这文件一般是用于回滚操作的。一旦事务执行rollback操作时候,这文件就记录的信息就进行回滚。他主要保证了事务原子性。

我们事务执行时候可能会出现的现象:

当事务执行到一半时候,突然断电或数据库宕机等各种异常情况。

当事务执行过程中突然遇到ROLLBACK指令时候,进行回滚操作。

这里面存放的是事务的反向操作。例如:

事务中的insert操作,undo_log中记录的就是delete操作。

事务中的delete操作,undo_log中记录的就是insert操作。

事务中的update操作把字段值从a改成b,undo_log中记录的就是update操作把b改成a。

存储内容是按照mvcc(多版本并发控制)方式来进行存储的。

例如

数据结构

id               int                                主键id

name        varchar(64)              名字

sex            tinyint                           性别

undo_log中存储的内容可能是

idnamesextrx_idroll_pointer
1test110000x111
1我的名字110000x222
1我的名字0nullnull

trx_id:这里面存放的内容是事务id。

roll_pointer:这里存放内容是回滚指针,例如上面表格所示,第一条数据的roll_pointer指向第二条的地址,通过这样的联系把有关联的串在一起,形成一个版本链。ps:insert是不会有roll_pointer值。

如果发生回滚时候,就会根据这版本链进行恢复数据。

如果发生的是事务提交操作,那么这undo_log就没什么用了,等到后台线程中的master thread或purge thread进行回收操作。

bin_log

主要有2个作用:

1.数据恢复(文章后半部分)

2.数据库集群

bin_log这是二进制文件,里面记录的信息是每次数据库执行的insert(新增),update(修改),delete(删除)操作时候,记录的命令行,每次有对应操作向后追加信息。集群时候数据库和数据库之间数据同步通过这bin_log来进行的。

事务带来的问题

事务深度问题

从上面redo_log的操作,我们能看出来,事务一开始时候MySQL会去数据页中拿事务相关的数据放在缓冲池中,我们如果事务执行的操作太多,这样数据页大量的信息会放在缓冲池中,就会消耗大量的内存,需要等到这事务操作提交或回滚,缓冲池的数据才能被释放。

脏读(Dirty read)

当一个事务正在访问数据并且对其进行了修改,但是还没提交事务,这时另外一个事务也访问了这个数据,然后使用了这个数据,因为这个数据的修改还没提交到数据库,所以另外一个事务读取的数据就是“脏数据”,这种行为就是“脏读”,依据“脏数据”所做的操作可能是会出现问题的。

修改丢失(Lost of modify)

是指一个事务读取一个数据时,另外一个数据也访问了该数据,那么在第一个事务修改了这个数据之后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,这种情况就被称为修改丢失。例如:事务1读取表中数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果都是19,但是事务1的修改记录丢失了。

不可重复读(Unrepeatableread)

指在一个事务内多次读取同一数据,在这个事务还没结束时,另外一个事务也访问了这个数据并对这个数据进行了修改,那么就可能造成第一个事务两次读取的数据不一致,这种情况就被称为不可重复读。

幻读(Phantom read)

幻读与不可重复读类似,幻读是指一个事务读取了几行数据,这个事务还没结束,接着另外一个事务插入了一些数据,在随后的查询中,第一个事务读取到的数据就会比原本读取到的多,就好像发生了幻觉一样,所以称为幻读。

事务隔离级别

说起MySQL的事务,自然首当其冲要先聊到他的事务隔离级别,不同的隔离级别,对事务的处理方式都不相同。

1.读未提交(READ-UNCOMMITTED)

读取还没提交的事务数据。可能造成脏读、不可重复读、幻读。

2.读已提交(READ-COMMITTED)

允许读取并发事务已经提交的数据,可以避免脏读,但是可能造成不可重复、幻读。

3.可重复读(REPEATABLE-READ)

MySQL默认事务隔离级别,对同一字段多次读取的结果都是一致的,除非本身事务修改,可以避免脏读和不可重复读,但是可能造成幻读。

会使用next lock锁进制,来防止幻读问题,但是引入锁进制后,锁的代价会比较高,比较耗费CPU资源,占用系统性能。

4.串读(SERIALIZABLE)

完全服从ACID的隔离级别,这是事务的最高级别,在每条读的数据上,加上锁,使之不可能相互冲突,可以避免脏读、不可重复读、幻读,但是事务的并发度就没有了。

  • 34
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值