隔离级别
之所以会有事务隔离一说,是由于不同事务的执行并不是串行化,而是并发的。所以事务才会 有不同的隔离级别的说法。
比如 未提交读,这个隔离级别 就会引发读脏数据。即 一个事务读了另一个事务未提交的数据,一旦另一个事务回滚。那这个事务读的就是脏数据。
比如 提交读 , 这个隔离级别 会出现不可重读现象。就是一个事务中,由于另外一个事务在这期间执行了insert 或者update delete操作 ,导致这个事务 前后读同一条记录读到的数据就不一致。更别提范围读了。
为啥呢,就是因为锁的原因。如果一个事务第一次读操作是select for update 直接弄上了行锁,那其他的事务不管怎么都没法改这行记录了,第一个事务再次发生读操作时,数据还是原来的数据。就不会出问题了。
比如 可重复读,当然就是说 在一个事务中 读某条记录读第一次 和第二次没差别。就是说其他事务的插入是被禁止的。但是 还是无法防止幻读。因为事务里面的select并没有加范围锁。
串行化 隔离级别当然可以防止任何问题,但是效率低下。所以当然不采用。所以Mysql默认级别是可重复读。这隔离级别已经很高了。
锁
比如有表t:
id name age
1 zw 25
4 mm 18
6 zz 8
先是三个基本锁:
记录锁 锁定索引记录;
注意,InnoDB的行锁是实现在索引上的,而不是锁在物理行记录上。潜台词是,如果访问没有命中索引,也无法使用行锁,将要退化为表锁。
间隙锁 锁定间隔,防止间隔中被其他事务插入;
(1,4) (4,6)
临键锁 锁定索引记录+间隔,(还包括第一条记录之前 和 最后一条记录之后)防止幻读;
(-无穷,1)[1,4) [4,6) [6,+无穷)
然后再看其他锁:
乐观锁
程序自己实现,一般的实现乐观锁的方式就是在数据库多放一个字段记录数据版本version。
实现数据版本有两种方式,
第一种是使用版本号,
第二种是使用时间戳。
悲观锁
for udate 排他锁
在事务开始后,使用排他锁的目的 是为了后续执行update修改。正如它的名字for update 一样。
这种锁是强一致性锁,就是说:
事务A执行了select id from t where status = 2 for update(status是锁引,则在该行记录加行锁,如果status 不是索引,那加的就是表锁了),
事务B再执行select id from t where status = 2 for update 时,是阻塞的。
事务C执行 select id from t where status = 2 lock in share mode时。也是阻塞的。
但是 如果执行select id from t where status = 2 时,不阻塞。
因为Innodb引擎默认的select 是不加锁的,直接读取已提交的事务保存的快照版本数据。
Innodb引擎默认的delete update操作是加了排他锁的。这样就保证了强一致性。
这种强一致性 就是保证了只有一个事务在执行修改。
lock in share mode 共享锁
事务A执行 select id from t where status = 2 lock in share mode时。
事务B执行 select id from t where status = 2 lock in share mode时,是可行的。
事务C执行 select id from t where status = 2 for update时。是阻塞的。
但是事务D执行 update/delete 操作 是阻塞的。
事务E执行 insert 操作 是不阻塞的。这个按道理也是不阻塞的。
---引用原话:
画外音:
-
排它锁是很强的锁,不与其他类型的锁兼容。这也很好理解,修改和删除某一行的时候,必须获得强锁,禁止这一行上的其他并发,以保障数据的一致性。
-
为了保证数据强一致,InnoDB使用强互斥锁,保证同一行记录修改与删除的串行性;
3.InnoDB使用插入意向锁,可以提高插入并发;讲解见下。
插入意向锁:
(insert 操作是个特殊的操作,比如存在插入意向锁这种锁 )
假设有表,在MySQL,InnoDB,RR下:
t(id unique PK, name);
10, shenjian
20, zhangsan
30, lisi
事务A先执行,在10与20两条记录中插入一行,还未提交:
insert into t values(11, xxx);
事务B后执行,也在10与20两条记录中插入一行:
insert into t values(12, ooo);
事务B是不阻塞的。
因为插入意向锁,相同索引区间,insert 进入不同行,所以就不会相互阻塞了。
索引
MyISAM 和InnoDB 索引分类:
InnoDB的索引有两类索引,聚集索引(Clustered Index)与普通索引(Secondary Index)
聚集索引 是一定存在的 且以主键作为索引,
没有表主键 会自动采用其他非重复列,
再咩有mysql内部也会自己创建一个id列。
普通索引 就是 辅助索引。如果用辅助索引查,则走两遍索引,
先查辅助索引 查主键
再根据聚集索引,查记录。
如 select * from t where name = "zw";
MyISAM也是有两类索引。叫非聚集索引,辅助索引。
非聚集索引类似InnoDB 聚集索引,辅助索引类似InnoDB辅助索引。
MyISAM 和InnoDB 索引的区别:
MyISAM 索引InnoDB索引
区别就是:
- MyISAM 索引文件 和 表记录数据 是单独分开的。由索引最后叶子节点里面主键对应的地址去表记录找。
- InnoDb 是直接索引结构最后叶子节点放的就是一条记录数据。
Mysql 和ISAM区别:
MyISAM不支持事务,不支持行锁 ,只有表锁,支持全文索引。
索引实现原理
直接看图
二叉搜索树
B-树
B+树
总结就是:
1. 二叉搜索层多。只有二叉。
2. B-树非叶子节点 叶节点 包含一整条记录数据 和指针。
而B+树 只是 叶子节点才带一整条记录,其他非叶子节点只带了key。
这样就能保证
1. 如果按页加载一页4K的数据,能从磁盘多加载很多key进入内存。从而减少磁盘IO。
2. 另外 B+树 最后叶子节点连成了链表结构。方便了范围查询。就是说只要从索引找范围的两端,找到两条记录。通过链表就完全确定了中间数据。
引用:
https://mp.weixin.qq.com/s/YMbRJwyjutGMD1KpI_fS0A
http://blog.codinglabs.org/articles/theory-of-mysql-index.html
网友评论