什么是事务
事务就是一荣俱荣一损俱损。
事务的特性
经典的ACID ————原子性 一致性 隔离性 持久性
原子性
事务中的sql为一个不可分割的小单元,原子性就是这个单元内的sql无法只执行一部分。
一致性
一致性保证事务执行前后的数据库是不矛盾的
隔离性
存在四个隔离级别:
隔离级别:
——自低向高——
RU 在一个事务执行的过程中可以看到另一个事务(未commit)对数据进行的修改
RC 在一个事务执行的过程中可以看到另一个事务(已commit)对数据进行的修改
RR 只要一个事务开始了 只有在这个事务提交后 才会看到 其他(已commit)事务对数据进行的修改
S 事务A先于事务B开启 那么事务A执行时会对操作的库进行上锁,执行完成再解锁。然后事务B执行。
(!!!不支持并发事务)
持久性
一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
ACID原理
原子性原理
BEGIN TRANSACTION 开始,以 COMMIT 或 ROLLBACK 结束
在一个事务完成时 成功——commit 失败——rollback
commit 则是将所有的操作持久化到数据库中
rollback 出现失误时,事务对所有完成的操作进行撤销,回滚到事务开始的时候。(查询的 操作不用)。这些记录都存在undolog里,也是由undolog进行回滚(逆向)操作。
持久性原理
innodb的存储都是存储在磁盘上的,那么频繁的IO操作是十分消耗性能的。
innodb提供的缓存池(Buffer Pool),他的机制是数据先保存再缓存池中,再在合适的机会(1、MySQL线程低于高水位;2、当有其他查询、更新语句操作该数据页时)完成持久化。同样在读数据时,同样先搜寻缓存池中有没有该数据,没有时再从磁盘读到缓存上。
这就是WAL机制。
那sql宕机是否缓存池中的数据会丢失?
这里引出了sql的日志
MySQL日志主要包括:
- 重做日志(redo log)
- 回滚日志(undo log)
- 归档日志(binlog)
- 错误日志(errorlog)
- 慢查询日志(slow query log)
- 一般查询日志(general log)
- 中继日志(relay log)
undo log & redo log & binlog 是其中较为重要的日志
上文所述 mysql 宕机 怎么保证缓存池文件仍然存在就是由 redo log & binlog 完成
实现:
在大量的数据需要进行持久化时 这时大量IO会导致数据库性能降低严重
所以这些记录都被保存在redo log中 在合适时机再写入
关于redo log :
redolog 是同时进行写入和清除的(循环写入和清除) 他是由一个固定大小的空间(400mb)。
这个时候数据库就有了crash-safe(落盘处理),当异常重启时数据仍然存在这个小磁盘空间上。
mysql分为 server层 和 引擎层
server层 :binlog 引擎层 : redo log
两者区别:
1)
binlog时用于恢复数据的,在上面记录的是物理记录(在哪修改了什么)
而在redolog上记录的是逻辑记录也就是原始的sql语句
2)
binlog是可追加写入 redolog是循环写入,会进行覆盖
在提交时必须使用两阶段提交
什么是两阶段提交,在执行器完成操作后,写入redolog 这个时候处于prepare状态,然后再写入binlog,将binlog写入磁盘,这个时候再将redolog的状态改为commit。
目的是避免数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。
并发场景下事务存在的数据问题
脏读
就是在事务A修改数据时 事务B可以查询这个未提交的数据
不可重复读
就是事务A在多次查询时 事务B可以在中间阶段修改数据 导致事务A多次查询的数据不一致
幻读
MySQL使用的InnoDB引擎默认的隔离级别是可重复读,也就是说在同一个事务中,两次执行同样的查询,得到的效果应该是一样的。因此,尽管B事务在A事务还未结束的时候,增加了表中的数据,但是为了维护可重复读,A事务中不管怎么查询,是查询不了新增的数据的。但是对于真实的表而言,表中的数据是的的确确增加了。
A查询不到这个数据,不代表这个数据不存在。查询得到了某条数据,不代表它真的存在。这样是是而非的查询,就像是幻觉一样,似真似假,故为幻读。
产生幻读的原因归根到底是由于查询得到的结果与真实的结果不匹配。