幻读针对的是多行,不可重复读针对的是一行
其实数据库mysql里面建索引,就相当于是数组里面的索引,如果一行记录中的某些列建立了索引,那么
B+树叶子节点都是 索引+非索引 这样的结构,建立索引的键放在前面,没有建立索引的列值放在后面
然后B+树叶子节点上面存放的就是叶子节点中最小的索引再加页号
辅助索引,就是你单独建立的关联索引 + 主键,找到这个节点之后,就可以根据这个主键,回表查到整行的数据
找数据:先通过辅助索引+回表
辅助索引:就是你另外建立的索引+主键本身的索引。找主键
回表:就是按照主键来确定具体是哪一行。找具体哪一行
最左前缀法则
隔离性
读已提交:
同一条数据:同一条数据两次查,不一样,叫做不可重复读
整张表:两次查不一样,幻读
可重复读
可能会出现幻读,但InnodB里面有一个锁,解决了幻读现象
每一行里面其实还有个事务ID,就是最近修改这行数据的事务ID
每次修改一个数据的时候,这个数据肯定要存起来,这时候,有一个版本链,存的就是每次修改时候的情况,每次修改肯定有一个不同的事务Id,然后就把每次的事务Id和这次修改的数据存起来。都时候去select的时候,就可以根据你的事务ID就可以找到这条数据了
在可重复读的隔离下,readView里面的内容是不变的,不管其他的事务是否已经提交,事务A在select的时候,都是按照以前的readView来查询数据的。
readView里面当前活跃的ID就是还没有提交的事务ID,在读已提交的隔离级别下,事务A每次读到的readView都是最新的,而在可重复读的隔离级别下,事务A每次读到的都是
读写锁
一行记录如果加了写锁,但是select * 这样的语句是不加任何的锁的,因此即使加了写锁,select 语句仍然能执行,一个资源可以加多个读锁,但只能加一把写锁
单纯的select * 是不带任何锁的,即使这行数据加了写锁,照样可以select
锁是在事务之中用的,你一旦commit,事务结束了,锁就释放了
select * from … for update 是把查出来的行进行加锁
在可重复读的隔离级别下
会有间隙锁
查询时是走索引的,那么查询的结果会全部加锁,如果是查找范围的话,那么这个范围里面全部都有加锁,包括间隙锁。 如果不是查找范围,只是where e = “b” 的话,那么根据这个e字段进行排序,order by e之后,你insert into 一条记录之后,如果order by e之后,你insert 的这条记录是在之前 select * from … where e = “b” order by e的附近的话,那么就会加锁,附近的都会加锁…
如果查询没有走索引,where 后面的字段没有加索引,select * from … where a = … 这里的a没有加索引,那么全表都会加锁