MVCC
MVCC的全称是“多版本并发控制”。这项技术使得InnoDB的事务隔离级别下执行一致性读操作有了保证,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。这是一个可以用来增强并发性的强大的技术,因为这样的一来的话查询就不用等待另一个事务释放锁。这项技术在数据库领域并不是普遍使用的。一些其它的数据库产品,以及mysql其它的存储引擎并不支持它。
InnoDB会给数据库中的每一行增加三个字段,它们分别是DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID,对于事务会用到两个
一个字段是记录创建时间
一个字段是记录过期时间
实际存储的是事务的版本号 每开启一个事务,事务的版本号递增
在mysql的默认隔离级别下 可重复读:事务A读取数据后,再次读取时读到了事务B已经提交的修改数据,导致两次读取的数据不一致,不符合隔离性
不能解决幻读
增删查改如下
插入 将创建时间记录为当前版本号
删除 将过期时间记录为当前版本号
修改 插入一条新的数据,创建时间记录为当前版本号,将旧的数据的过期时间记录为当前版本号
查询 查询创建时间小于或等于当前版本号,并且过期时间为空或者大于当前版本的数据
可重复读解决了幻读问题?
mysql的可重复读的隔离级别解决了读的幻读问题,不能解决更新的幻读问题
dept表中有一条数据后勤部门
事物 1 | 事物 2 |
---|---|
begin | begin |
select * from dept | |
- | insert into dept(name) values("研发部") |
- | commit |
update dept set name="财务部" | |
commit |
根据上面的结果我们期望的结果是这样的:
1.财务部
2.研发部
但实际的查询结果是
1.财务部
2.财务部
本来我们希望得到的结果只是第一条数据的部门改为财务,但是结果确实两条数据都被修改了。
这种结果告诉我们其实在MySQL可重复读的隔离级别中并不是完全解决了幻读的问题,而是解决了读数据情况下的幻读问题。而对于修改的操作依旧存在幻读问题,就是说MVCC对于幻读的解决时不彻底的。
当前读和快照读
select快照读
InnoDB 给每一个事务生成一个唯一事务 ID 的方法称为生成快照
快照读就是读取的历史版本,执行select操作默认就是快照读
当前读
当前读的场景有一下几种
update、 delete 、insert select ... lock in share mode (共享读锁) select ... for update (写锁) |
---|
当前读,读取的是最新版本,并且对读取的记录加锁,阻塞其他事务同时修改相同记录,避免出现安全问题。
例如,假设要update一条记录,但是另一个事务已经delete这条数据并且commit了,如果不加锁就会产生冲突。所以update的时候肯定要是当前读,得到最新的信息并且锁定相应的记录。
MySQL 中事务开始的时间
一般我们会认为 begin/start transaction 是事务开始的时间点,也就是一旦我们执行了 begin/start transaction,就认为事务已经开始了,其实这是错误的。事务开始的真正的时间点(LSN),是 start transaction 之后执行的第一条语句,不管是什么语句,不管成功与否。
但是如果你想要达到将 start transaction 作为事务开始的时间点,那么我们必须使用:
start transaction with consistent snapshot
它的含义是:执行 start transaction 同时建立本事务一致性读的 snapshot . 而不是等到执行第一条语句时,才开始事务,并且建立一致性读的 snapshot .
效果等价于: start transaction 之后,马上执行一条 select 语句(此时会建立一致性读的snapshot)。