经过前面的步骤生成的语法树被认为是合法的了,并且由优化器将其转化成查询计划。多数情况下,一条查询可以有很多种执行方式,最后都返回相应的结果。优化器的作用就是找到这其中最好的执行计划。
MySQL使用基于成本的优化器,它尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最小的一个。在MySQL可以通过查询当前会话的last_query_cost的值来得到其计算当前查询的成本。
数据库事务的概念及其实现原理
数据库事务(Database Transaction)概述
什么是事务?
- 转账的例子
- 1.转账操作的第一步执行成功,A账户上的钱减少了100元,但是第二步执行失败或者未执行便发生系统崩溃,导致B账户并没有相应增加100元。
- 2.转账操作刚完成就发生系统崩溃,系统重启恢复时丢失了崩溃前的转账记录。
- 3.同时又另一个用户转账给B账户,由于同时对B账户进行操作,导致B账户金额出现异常。
- 1.将A账户的金额减少100元
- 2.将B账户的金额增加100元。
- 从A账户转账100元到B账号。站在用户角度而言,这是一个逻辑上的单一操作,然而在数据库系统中,至少会分成两个步骤来完成:
- 在这个过程中可能会出现以下问题:
- 为了便于解决这些问题,需要引入数据库事务的概念。
- 定义
- 数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
- 必须满足ACID属性
- 例子
- 一个典型的数据库事务如下所示
BEGIN TRANSACTION //事务开始 SQL1 SQL2 COMMIT/ROLLBACK //事务提交或回滚
为什么要有事务?
- 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
- 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
ACID 特性
- 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
- 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态,一致状态的含义是数据库中的数据应满足完整性约束。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
- 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
隔离级别
- 四个级别
- Read Uncommitted 读未提交:就是一个事务可以读取另一个未提交事务的数据。
- Read Committed 读提交:就是一个事务要等另一个事务提交后才能读取数据。若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。
- Repeatable Read 重复读:就是在开始读取数据(事务开启)时,不再允许修改操作。重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。
- Serializable 顺序读:是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
- mysql 对应的InnoDB默认隔离级别是 重复读
- 所有事务隔离级别都不允许出现脏写,而串行化可以避免所有可能出现的并发异常,但是会极大的降低系统的并发处理能力。
- 共享锁与排它锁
- 排它锁
- 共享锁
- 读
- 写
- 隔离怎么实现?
- 共享锁(S锁) :(插入/修改/删除)资源获取S锁之后,能加S锁,不能加X锁
- 排它锁(X锁) :资源加上X锁之后,不能加S锁,也不能加X锁
- 锁
- InnoDB存在两种锁
数据库事务实现原理剖析
事务的实现原理
- 事务的执行过程
- 系统会为每个事务开辟一个私有工作区
- 事务读操作将从磁盘中拷贝数据项到工作区中,在执行写操作前所有的更新都作用于工作区中的拷贝.
- 事务的写操作将把数据输出到内存的缓冲区中,再由缓冲区管理器将数据写入到磁盘。
- 分特性
- 锁
- MVCC 多版本并发控制
- 人们一般把基于锁的并发控制机制称成为悲观机制,而把MVCC机制称为乐观机制。这是因为锁机制是一种预防性的,读会阻塞写,写也会阻塞读,当锁定粒度较大,时间较长时并发性能就不会太好;而MVCC是一种后验性的,读不阻塞写,写也不阻塞读,等到提交的时候才检验是否有冲突,由于没有锁,所以读写不会相互阻塞,从而大大提升了并发性能。
- 通过增加系统版本号,每次事务操作,会比较系统版本号
- InnoDB为每行记录添加了一个版本号(系统版本号),每当修改数据时,版本号加一。在读取事务开始时,系统会给事务一个当前版本号,事务会读取版本号<=当前版本号的数据,这时就算另一个事务插入一个数据,并立马提交,新插入这条数据的版本号会比读取事务的版本号高,因此读取事务读的数据还是不会变。
- MVCC 是什么?
- 基于CAS(Compare-and-swap)
- 有条件更新(Conditional Update)
- 通过undo log 来实现
- 原子性是事务的基本特性,保证了事务中的操作是不可拆分的整体,那么原子性是如何实现的呢?事务的原子性表现的两个方面:
- 通过redo log 来实现
- 事务提交失败,那么事务中的操作都失败,这个是通过数据库的撤销操作日志来保证的,也称之为undo log。
- 事务提交成功保证事务中的操作都会完成。1、是正确执行完事务,没有出现任何问题;2、是事务提交成功但是出异常,数据库恢复之后,提交完成的事务会保证数据库完成该事物的操作。对于第一种正常情况不予讨论,因为不存在 异常情况,那么第2种实际上是和上文说的持久性是相关联的,而这个是基于重做日志(redo log)来保证提交完成的事务在异常情况下保证数据操作能够进行:
- 事务提交成功时,那么事务中的操作总会完成
- 事务提交失败,那么事务中的操作都失败
- 原子性
- 一致性
- 隔离性
- Undo原理 与 Redo原理
- 和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。
- 在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo Log)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
- Undo原理:(备份旧数据)
- Redo原理:(保存最新数据)
end:如果你觉得本文对你有帮助的话,记得关注点赞转发,你的支持就是我更新动力。