提到事务, 你肯定不陌生, 和数据库打交道的时候, 我们总是会用到事务, 最经典的例子就是转账, 你要给朋友小王转100块钱, 而此时你的银行卡只有100块钱.
转账过程具体到程序里会有一系列的操作, 比如余额查询, 做加减法, 更新余额等, 这些操作必须保证是一体的, 不然等程序查完之后, 还没做减法之前, 你这100块钱, 完全可以借着这个时间差再查一次, 然后再给另外一个朋友转账, 如果银行这么整, 不久乱了么?, 这是就要用到”事务”这个概念了.
简单来说, 事务就是要保证一组数据库操作, 要么全部成功, 要么全部失败. 再mysql中, 事务支持是在引擎层实现的.你现在知道, mysql是一个支持多引擎的系统, 但并不是所有的引擎都支持事务.比如mysql原生的myiSAM引擎就不支持事务, 这也是MyISAM被InnoDB取代的重要原因之一.
隔离性和隔离级别
提到事务, 你肯定会想到ACID(Atomicity, Consistency, isolation, DURability, 即原子性, 一致性, 隔离性, 持久化).
当数据库上游多个事务同时执行的时候, 就可能出现脏读(dirty read), 不可重复读(non-repeatable read), 幻读(phantom read)的问题, 为了解决这些问题, 就有了”隔离级别”的概念.
在谈隔离级别之前, 你首先要知道, 你隔离得越严实, 效率就会越低.因此很多时候, 我们都要在二者之间寻找一个平衡点.sql标准的事务隔离级别包括: 都未提交(read uncommitted), 读提交(read committed), 可重复读(repeatable read)和串行化(seriazable).
- 读未提交是指, 一个事务还没提交时, 他做的变更就能被别的事务看到.
- 读提交是指, 一个事务执行过程中看到的数据, 总是跟这个事务在启动时看到的数据是一致的,当然在可重复读隔离级别下, 未提交变更对其他事务也是不可见.
- 串行化, 顾名思义是对于同一行记录, “写”会加”写锁”, “读”会加”读锁”. 当出现读写锁冲突的时候, 后访问的事务必须等前一个事务执行完成, 才能继续执行.
其中”读提交”和”可重复读”比较难理解, 所以我用一个例子说明这几种隔离级别.假设数据表T中只有一列, 其中一行的值为1, 下面是按照时间顺序执行两个事务的行为.
1 | mysql> create table T(c int) engine=InnoDB; |
我们来看看在不同的隔离级别下, 事务A会有那些不同的返回结果, 也就是图里面V1, V2,V3的返回值分别是什么.
在mysql里, 有两个”视图”的概念:
一个是view.它是一个用查询语句定义的虚拟表, 在调用的时候执行查询语句并生成结果,创建视图的语法是create view…, 而他的查询方法与表一样.
另一个是InnoDB在实现mvcc时用到的一致性读视图, 即consistent readview, 用于支持RC(read committed, 读提交)和RR(Repeatable Read, 可重复读)隔离级别的实现.