1.事务
首先要明白事务的概念: 他是sql执行的一个基本单位,可以是一个简单的SQL 也可以是一组复杂 的SQL ,事务就保证 这些操作,要么全部成功,要么全部失败,
事务的 开始与结束 可以由用户来控制。如果用户没有显示的定义事务,则由数据库管理系统按默认规定自动划分事务。在 SQL 中,定义事务的语句一般有三条:
(1)BEGIN TRANSACTION
(2)COMMIT
(3)ROLLBACK
事务通常是以BEGIN TRANSACTION 开始,以 COMMIT 或 ROLLBACK 结束。COMMIT 表示提交,即提交事务的所有操作。具体的说就是将事务中的所有对数据库的更新写回到磁盘上的物理数据库中,事务正常结束。ROLLBACK表示回滚,即在事务中运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库所有已完成的操作全部撤销,回滚到事务开始时的状态,这里的操作指对数据库的更新操作。
2.ACID
A(Atomicity):原子性
原子性是指事务是一个不可分割的工作单位,事务中操作要么都发生,要么都不发生。
C(Consistency):一致性
数据库由一种状态到另一种状态,事务前后的数据库的完整性约束没有被破坏,数据必须保持一致
I(Isolation):隔离性
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务所干扰,多个并发事务之间要相互隔离。
D(Durability):持久性
持久性是指一个事务一旦被提交,它对数据库中的数据改变是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。 (事务系统的高可靠性)
3.ACID 事务的实现
原子性是通过 undo log来实现的。
持久性是通过redo log来实现的。
隔离性是通过 (读写锁+MVCC)来实现的。
一致性是通过原子性,持久性,隔离性来实现的!!!
3.1 原子性 undo log
当发生错误异常或者显示的执行rollback语句时候,需要把数据还原到原先的模样 , 所以这时候也就需要利用 undo log 日志 来进行回滚
首先 undo log 生成:
(1)每条数据变更(insert/update/delete)操作都伴随一跳undo log的生成,并且回滚日志必须先于数据持久化到磁盘。
(2)所谓的回滚就是根据回滚日志做逆向操作,比如 delete 的逆向操作为 insert ,insert的逆向操作为delete,update的逆向为update等。
根据 undo log 进行回滚 :
为做到同时成功或者失败,系统发生错误或者执行 rollback 操作时需要根据 undo log 进行回滚。
回滚操作就是要还原到原来的状态,undo log记录了数据被修改前的信息以及新增和被删除的数据信息,根据undo log生成回滚语句,比如:
(1) 如果在回滚日志里有新增数据记录,则生成删除该条的语句
(2) 如果在回滚日志里有删除数据记录,则生成生成该条的语句
(3) 如果在回滚日志里有修改数据记录,则生成修改到原先数据的语句
3.2 持久性 (redo log 预写式日志)
MySQL的表数据是存放在磁盘上的,因此想要存取的时候都要经历磁盘 IO,是非常消耗性能的。为了提升性能 InnoDB 提供了缓冲池(Buffer Pool),Buffer Pool 中包含了磁盘数据页的映射,可以当做缓存来使用,每个数据页大小固定的16 kb
读数据:会首先从缓冲池中读取,如果缓冲池中没有,则从磁盘读取在放入缓冲池;
写数据:会首先写入缓冲池,缓冲池中的数据会定期同步到磁盘中;
但是它也带来了新的问题,当MySQL系统宕机,断电的时候可能会丢数据!!!
因为我们的数据已经提交了,但此时是在缓冲池里头,还没来得及在磁盘持久化,
所有 redo log就派上用场了
既然redo log也需要存储,也涉及磁盘IO为啥还用它?
(1)redo log 的存储是顺序io存储文件追加的方式,而缓存同步是随机操作。
(2)缓存同步是以数据页16kb为单位的,每次都要操作所有的,传输的数据大小
大于 redo log的操作数据 ,redo log 只写需要用的数据。
日志持久化的方式:
- 当提交了事务,并不是直接将缓冲区的 redo 日志写入 磁盘的日志文件,而是等待主线程刷新
- 当事务提交时,将缓冲区的redo 日志 同步写入 磁盘,这保证了一定会成功事务提交时(默)
- 使用异步写入日志文件进入磁盘,但不能保证commit时肯定会写入日志文件
3.3 隔离性 (锁 + mvcc)
写-写操作 : 锁
写-读操作 : MVCC (多版本并发控制)
脏读 :一个事务读取到了其他事务没有提交的数据。
解决:读取是加共享锁,读取完立马就能释放锁,更新时加排他锁,更新提交后才能释放锁不可重复读 :一个事务对同一行记录两次读取结果不同。(中间其他人改了数据)
解决:加共享锁和排他锁,都是在事务提交后才才释放锁幻读 :一个事务对同一范围的两次查询结果不同,
比如,事务1修改了一个范围内的数据。事务2在事务1刚修改完数据还没提交的时候又给这个范围插入了一条数据,然后事务1发现范围内还有没修改的数据行。像出现了幻觉
解决方法:需要加范围锁
事务隔离级别:
MVCC 在 MySQL InnoDB 中实现主要是为了提高数据库并发性能,做到读可不加锁,读写不冲突。并发性能很高。逻辑是维持一个数据的多个版本,使得读写操作没有冲突,读-写的无锁控制
InnoDB是在undo log中实现多版本并发,通过undo log可以找回数据的历史版本。
找回的数据历史版本可以提供给用户读,也可以在回滚的时候覆盖数据页上的数据
3.4 一致性
数据库总是从一个一致性的状态转移到另一个一致性的状态。
通过回滚,以及恢复,和在并发环境下的隔离做到一致性。
分享一份关于mysql 的思维导图,含有核心知识点
MySQL (processon.com)https://www.processon.com/embed/626e83a16376891e1c1ee8ff