数据库基础知识
1、ACID:
mysql相关日志:
逻辑备份日志:binlog
(物理)重做日志:redolog
回滚日志:undolog
锁技术+MVCC
原子性(atomicity):
-
强调单个事务不可分割,
-
全部commit,否则全部rollback
-
undolog实现异常回滚
每条数据变更:INSERT UPDATE DELETE REPLACE产生一条undolog日志,sql执行前优先于数据持久化到磁盘 insert: rollback时执行delete delete:回滚时会执行insert; update: 回滚时会执行相反的update,把数据改回来
- 记录事务开始前老版本数据,用于实现回滚,保证了原子性,实现MVCC,将数据修改前的旧版本保存在undolog,行记录有隐藏字段回滚指针指向老版本
一致性(Consistency):
- 数据库总是从一个一致性的状态转换到另外一个一致性的状态
- 过程中系统崩溃,事务未提交,不影响结果
- 通过aid来确认数据的最终一致性
隔离性(isolation):
- 多个事务,操作隔离
- 避免并发事务产生影响
- 读写锁+MVCC
持久性:(durability)
- 一旦提交,其所做的修改就会永久保存到数据库中
- 即使后面出现故障,也不会影响原来的结果
- binlog+redolog实现
- 表数据持久化到磁盘,为了保证在并发持久化的情况下不影响效率,引用了缓存池(包含了磁盘中部分数据页的映射,可以当作缓存使用)
- 当修改表数据时,将操作记录先写到buffer pool中,标记事务已完成,等mysql空闲时,再将更新操作持久化到磁盘,从而缓解MySQL并发压力
redolog:记录事务开启之后对数据做的修改(crash-safe)
介绍:
- WAL技术:全称是Write-Ahead Logging,关键点:先写日志,再写磁盘、
- 特性:空间一定,写完后会循环写,有两个指针write pos指向当前记录位置,checkpoint指向将擦除的位置,redolog相当于是个取货小车,货物太多时来不及一件一件入库太慢了这样,就先将货物放入小车,等到货物不多或则小车满了或则店里空闲时再将小车货物送到库房。用于crash-safe,数据库异常断电等情况可用redo log恢复。
写入流程:
- 先写redo log buffer
- write到文件系统的page cache
- fsync持久化到磁盘
写入策略:
根据innodb_flush_log_at_trx_commit参数控制(innodb以事务的什么提交方式刷新日志
- 0:事务提交时只把redo log 留在redo log buffer
- 1:将redo log直接持久化到磁盘(所以有个双“1”配置,后面会讲)
- 2:只是把redo log写到page cache
2、并发事务产生的问题以及对应隔离级别
InnoDB在实现MVCC时用到的一致性读视图,即consistent read view,用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。
2.1、产生的问题:
脏读:(dirty read)
- 事务A读到事务B未提交的数据
丢失修改:(lost to modify)
- 两事务A和B同时操作某一数据,最先执行完的事务的修改被丢失
- 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-2,最终结果A=18,事务1的修改被丢失。
不可重复读(Unrepeatableread)
- 一个事务里多次读同一个数据,在这个事务还没有结束,有另一个事务修改了数据,导致多次读取数据不一致
- 并发事务修改
幻读(Phantom read)
- 并发事务新增或者删除
- 一个事务里多次读同一个数据,在这个事务还没有结束,有另一个事务新增或者删除了数据,导致多次读取数据行数不一致
2.2、事务隔离级别:
Mysql8以前:SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
Mysql8开始:SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;
修改事务隔离级别:
SET SESSION(GLOBAL) TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
读未提交:(Read uncommitted)
- 事务最小限度的隔离
- 一个事务可以读取另一个未提交事务的数据。
- 会出现脏读
读已提交:(rc)
- 可以看到其他事务对数据的修改。
- 在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的同一sql在其他事务执行前后返回的是不同的结果。(不可重复读)
- 一个事务要等另一个事务提交后才能读取数据
- 解决了脏读,丢失修改,会出现不可重复读
- Oracle默认该级别
可重复读(rr):
- 在开始读取数据(事务开启)时,不再允许其他事务的修改操作
- 在事务执行期间会锁定该事务以任何方式引用的所有行
- 解决了不可重复读,但会存在幻读情况
- 此隔离级别下,未提交变更的事务对其他事务也是不可见的
- MVCC解决了不可重复读:MVCC保留对象的多个不同版本,读事务读取时,先确定对象当前已提交的最新版本,然后该事务会一直读取这个版本的数据,哪怕在读事务运行过程中对象提交了新的版本。
Serializable(可串行化)
- 事务顺序执行,性能依次最差
- 解决了幻读
- 它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
- 每次读都需要获得表级共享锁,读写相互都会阻塞