MySQL 事务分析
当前事务使用的过程中,主要对于数据更新以及读取过程中,结果不一致出现的概念:
事务:
当前的操作要么全部失败,要么全部成功,
并发控制的基本单位
其中 Innodb 的存储引擎,对于数据库--> 支持事务,行锁
ACID
(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)
隔离级别的由来:
因为多个事务执行的过程中会出现, 脏读,不可重复读,幻读的问题;
提出了解决这些问题的--事务的隔离级别:
读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )
- 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
- 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
- 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
- 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。
1.在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。
2.在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。
3.这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;
4.而“串行化”隔离级别下直接用加锁的方式来避免并行访问
每条记录更新时,变更记录记载在 redo log,回滚记录记载在 undo log
将一个值从 1-4,
redolog 日志会记录变更的日志信息, undo log 日志会记录 回滚的视图日志信息
也就是说,现在值为 4,我想回滚操作,就从 undo log 日志去取回滚操作日志的视图
事务的启动方式:
默认是自动提交事务, 一个 sql 语句代表一个事务,遵循 ACID 的特性,然后我们开始使用具体的操作;
因为默认是自动提交的,所以我们首先要取消自动提交;手动提交事务;
但是很多客户端和框架,会 自动取消提交事务,导致长链接事务,一直等待 commit/rollback, 或者断开
所以比较中肯的方案是,每次都提交事务, 并且自动开启下一个事务;
在 autocommit 为 1 的情况下,用 begin 显式启动的事务,如果执行 commit 则提交事务。
如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行 begin 语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。
两阶段提交的方式:
对于上讲的两阶段提交, redo log 日志是关于物理 ,bin log 是对于逻辑性,备份用的
因为是两阶段提交,这时候 redolog 只是完成了 prepare, 而 binlog 又失败,那么事务本身会回滚,所以这个库里面 status 的值是 0。
如果通过 binlog 恢复出一个库,status 值也是 0。
这样不算丢失,这样是合理的结果。
过程细节分析
1 prepare 阶段 2 写 binlog 3 commit
当在 2 之前崩溃时
重启恢复:后发现没有 commit,回滚。备份恢复:没有 binlog 。
一致
当在 3 之前崩溃
重启恢复:虽没有 commit,但满足 prepare 和 binlog 完整,所以重启后会自动 commit。备份:有 binlog. 一致
版权声明: 本文为 InfoQ 作者【卢卡多多】的原创文章。
原文链接:【http://xie.infoq.cn/article/6f7add2c18a35de70e9ededab】。文章转载请联系作者。
评论