Java 进阶JVM · Java虚拟机原理 · JVM上语言·框架· 生态系统编程语言爱好者

mysql事务

2020-11-03  本文已影响0人  我犟不过你

参考:https://www.cnblogs.com/kismetv/p/10331633.html

一、mysql逻辑架构图

逻辑架构图

mysql架构主要分为三层:
(1)第一层:处理客户端连接、授权认证等。
(2)第二层:服务器层,负责查询语句的解析、优化、缓存以及内置函数的实现、存储过程等。
(3)第三层:存储引擎,负责MySQL中数据的存储和提取。MySQL中服务器层不管理事务,事务是由存储引擎实现的。MySQL支持事务的存储引擎有InnoDB、NDB Cluster等,其中InnoDB的使用最为广泛;其他存储引擎不支持事务,如MyIsam、Memory等

二、四大特性ACID

衡量事务的四个维度,一般很难完全实现,mysql的innodb默认支持的可重复读,oracle默认支持读已提交,均不支持隔离性。

原子性:Atomicity
一致性:Consistency
隔离性:Isolation
持久性:Durability

2.1 mysql的日志分类

名称 作用
redo log(重做日志) 确保日志的持久性,防止在发生故障,脏页未写入磁盘。重启数据库会进行redo log执行重做,达到事务一致性
undo log(回滚日志) 保证数据的原子性,记录事务发生之前的一个版本,用于回滚,innodb事务可重复读和读取已提交 隔离级别就是通过mvcc+undo实现
err log(错误日志) Mysql本身启动,停止,运行期间发生的错误信息
slow query log (慢查询日志) 记录执行时间过长的sql,时间阈值可以配置,只记录执行成功
bin log (二进制日志) 用于主从复制,实现主从同步
relay log (中继日志) 用于数据库主从同步,将主库发来的bin log保存在本地,然后从库进行回放
general log (普通日志) 记录数据库的操作明细,默认关闭,开启后会降低数据库性能

2.2 原子性

要么都成功,有一个失败则全部要失败。数据库中若存在失败,则所有数据必须回滚。

原理 undo log

InnoDB实现回滚,靠的是undo log:当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

回滚的实现是通过具体操作的相反操作,比如insert对应delete,update在回滚时会将数据update为更新前的数据。

2.3 持久性

事务一旦经过提交,其对数据库的改变是永久性的,后续的操作或者故障不应对其产生影响。

原理:redo log

redo log出现的原因:Innodb是将数据存储在硬盘上的,无论写入必然需要磁盘IO,效率低下,为了解决这一问题,引入了Buffer Pool(缓冲池)。缓冲池包含磁盘中的部分数据页,当从读取数据时,会先在缓冲池进行查询,没有的话再去磁盘,同时更新数据到缓冲池。当像数据库写入数据时,会先写入到缓冲池中,缓冲池的数据会定期刷新到磁盘(刷脏)。

刷脏:当前缓冲池数据与磁盘数据不一致,被称为脏页,定时刷新脏页数据到磁盘的过程叫做刷脏。

缓冲池的存在引出的问题:如果刷脏过程还没进行就出现宕机,那么会出现丢失数据的问题,必然无法保证数据一致性。

鉴于上面的问题,redo log被引出用于解决以上问题。

当缓冲池的数据被修改时,会优先在redo log记载修改的操作记录(redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool)。事务提交时,通过调用fsync(参考下面的引申内容)接口对redo log进行刷盘。若果宕机的话,在重启是可以读取redo log的内容进行刷盘。

引申:

为了保证磁盘上实际文件系统与缓冲区中内容保持一致,unix提供了sync、fsync、fdatasync三个函数。

sync():只是将所有修改过的块缓冲区排入写队列,然后就返回,并不等待实际写磁盘操作结束。
fsync():只对由文件描述符filedes(与打开文件相对应)指定的单一文件起作用,且等待写磁盘操作结束,然后返回。该调用会阻塞等待直到设备报告IO完成。会将文件的元数据等一同写在磁盘上。
fdatasync():类似于fsync,但不保证文件的元数据会写入磁盘上。

fsync与fdatasync区别:除了同步文件的修改内容(脏页),fsync还会同步文件的描述信息(metadata,包括size、访问时间等等),因为文件的数据和metadata通常存在硬盘的不同地方,因此fsync至少需要两次IO写操作

在redo log当中,仍然存在redo log buffer这样的缓存区,仍然需要将redo buffer刷新到redo log file,参考文章:https://blog.csdn.net/weixin_38629422/article/details/105813338
可以通过下面的参数设置redolog刷新策略
innodb_flush_log_at_trx_commit
mysql推荐设置为1

innodb_flush_log_at_trx_commit的三种策略:
当为0时:不会在事务提交时将redo log buffer写入磁盘文件。
当为1时:在事务提交时,即将redo log buffer 写入磁盘文件redo log file中。
当为2时:会在事务提交时,首先将redo log buffer写入os cache,随后会在一定时间内将数据刷新到硬盘。

除了事务提交时,还有其他刷盘时机:如master thread每秒刷盘一次redo log等,这样的好处是不一定要等到commit时刷盘,commit速度大大加快。

2.4 隔离性

与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。

针对隔离性其实主要针对两个方面:
写写:一个正在写操作的事务对另一个正在写的事务事务是否有影响。锁机制保持隔离性。
写读:一个正在写操作的事务对另一个读取的事务是否有影响。MVCC保持隔离性。

2.4.1 写写操作

锁机制:innodb支持行级锁,而myisam支持的是表级锁。

查看锁的信息:
select * from information_schema.innodb_locks; #锁的概况
show engine innodb status; #InnoDB整体状态,其中包括锁的情况
2.4.2 写读操作
2.4.2.1 四种隔离级别
读未提交:READ UNCOMMITTED
读已提交:READ COMMITTED
可重复读:REPEATABLE READ
串行化:SERIALIZABLE 
隔离级别 脏读可能性 不可重复读可能性 幻读可能性
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

脏读:读取了事务未提交时的数据。
不可重复读:在一个事务过程中,多次相同查询得到了不同的结果。
幻读:一个事务(同一个read view)在前后两次查询同一范围的时候,后一次查询看到了前一次查询没有看到的行。参考https://www.jianshu.com/p/c53c8ab650b5

MVCC(Multi-Version Concurrency Control,多版本并发控制)
mysql使用的是可重复读的隔离级别,那么必然会产生幻读的现象,通过使用MVCC(多版本并发控制)解决脏读,不可重复读,幻读问题。

实现MVCC的基本技术栈:
(1)隐藏列:InnoDB中每行数据都有隐藏列,隐藏列中包含了本行数据的事务id、指向undo log的指针等。
(2)基于undo log的版本链:每条undo log也会指向更早版本的undo log,从而形成一条版本链。
(3)ReadView:通过隐藏列和版本链,MySQL可以将数据恢复到指定版本;但是具体要恢复到哪个版本,则需要根据ReadView来确定。所谓ReadView,是指事务(记做事务A)在某一时刻给整个事务系统(trx_sys)打快照,之后再进行读操作时,会将读取到的数据中的事务id与trx_sys快照比较,从而判断数据对该ReadView是否可见,即对事务A是否可见。

2.5 一致性

一致性是指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。

可以说,一致性是事务追求的最终目标:前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。此外,除了数据库层面的保障,一致性的实现也需要应用层面进行保障。

上一篇下一篇

猜你喜欢

热点阅读