事务的ACID
- Atomic: 原子性,就是很多条sql,要不是一起执行成功,要么都不执行,或者都执行失败,不允许其中一部分成功,一部分失败,这样的话,就不是原子性了
- Consistency: 一致性,这是针对数据一致性来说的,就是一组sql执行之前,数据必须是正确的,执行之后,数据也必须是正确的,别弄半天,sql也执行完来,结果sql对应的数据修改没有给执行。
- Isolation: 隔离性,就是多个事务在执行的时候是互不干扰的,别事务A操作个数据,刚弄到一半的时候,事务B来把这个数据给改了,然后事务A操作失败。
- Durability: 持久性,事务成功了,就必须永远的对数据的修改是有效的,别过了一会儿,修改的数据自己不见了。
事务的隔离级别
- 读未提交,Read Uncommitted: 就是某个事务修改了一条数据,还没有提交的时候,另一个事务就把这修改的数据给读到了,这也叫脏读。
- 读已提交,Read Committed(不可重复读):就是事务A在跑的时候,先查询了一个数据的值是1,然后过了一段时间,事务B把事务A查出来的那个值给修改成2了,事务A再查询该数据时,该数据的值变成了2,就是事务A读取了事务B提交的数据,所以叫读已提交,也叫不可重复读,也就是说,在同一个事务里面,对同一个数据的值可能两次读取不一样。
- 可重复读,Repeatable Read : 事务A在执行过程中,对某个数据的值,无论读多少次都是一样的值,哪怕在这个过程中事务B修改了数据的值还提交了,但是事务A读到的还是自己事务开始时读到的值。
- 串行化:幻读,不可重复读和可重复读都是针对两个事务同时对某条数据在修改,但是幻读针对的是插入,比如某个事务把一个表中所有行的某一个字段的值修改为2,结果另一个事务过来,插入了一条数据,然后使的该行上面的该字段的值为1,然后第一个事务就会发现多出来一条数据,并且该字段的值为1。如果要解决幻读,就需要使用,串行化的隔离级别,所以的事务都串行起来,不允许多个事务并行操作。
MySQL的默认隔离级别
- Read Repeatable 可重复读
innodb存储引擎的实现原理
通过MVCC机制来实现的,就是多版本并发控制,multi-version concurrency control。
innodb存储引擎,会在每行数据的最后加两个隐藏列,一个保存行的创建时间,一个保存行的删除时间,但是这儿存放的不是时间,而是事务id,事务id是mysql自己维护的自增的,全局唯一。
事务id,在mysql内部是全局唯一递增的,事务id=1,事务id=2,事务id=3
id name 创建事务id 删除事务id
1 张三 120 122
2 李四 119 空
2 小李四 122 空
事务id=121的事务,查询id=1的这一行的时候,一定会找到创建事务id <= 当前事务id的那一行,select * from table where id=1,就可以查到上面那一行
事务id=122的事务,将id=1的这一行给删除了,此时就会将id=1的行的删除事务id设置成122
事务id=121的事务,再次查询id=1的那一行,能查到吗?能查到,要求创建事务id <= 当前事务id,当前事务id < 删除事务id
事务id=121的事务,查询id=2的那一行,查到name=李四
事务id=122的事务,将id=2的那一行的name修改成name=小李四
事务id=121的事务,查询id=2的那一行,答案是:李四,创建事务id <= 当前事务id,当前事务id < 删除事务id
在一个事务内查询的时候,mysql只会查询创建时间的事务id小于等于当前事务id的行,这样可以确保这个行是在当前事务中创建,或者是之前创建的;同时一个行的删除时间的事务id要么没有定义(就是没删除),要么是必当前事务id大(在事务开启之后才被删除);满足这两个条件的数据都会被查出来。
那么如果某个事务执行期间,别的事务更新了一条数据呢?这个很关键的一个实现,其实就是在innodb中,是插入了一行记录,然后将新插入的记录的创建时间设置为新的事务的id,同时将这条记录之前的那个版本的删除时间设置为新的事务的id。
现在get到这个点了吧?这样的话,你的这个事务其实对某行记录的查询,始终都是查找的之前的那个快照,因为之前的那个快照的创建时间小于等于自己事务id,然后删除时间的事务id比自己事务id大,所以这个事务运行期间,会一直读取到这条数据的同一个版本。
网友评论