美文网首页
事务隔离与锁与索引

事务隔离与锁与索引

作者: RedHatMe | 来源:发表于2018-09-01 01:54 被阅读0次

    隔离级别

    之所以会有事务隔离一说,是由于不同事务的执行并不是串行化,而是并发的。所以事务才会 有不同的隔离级别的说法。

    比如 未提交读,这个隔离级别 就会引发读脏数据。即 一个事务读了另一个事务未提交的数据,一旦另一个事务回滚。那这个事务读的就是脏数据。

    比如 提交读 , 这个隔离级别 会出现不可重读现象。就是一个事务中,由于另外一个事务在这期间执行了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 操作 是不阻塞的。这个按道理也是不阻塞的。

    ---引用原话:
    画外音:

    1. 排它锁是很强的锁,不与其他类型的锁兼容。这也很好理解,修改和删除某一行的时候,必须获得强锁,禁止这一行上的其他并发,以保障数据的一致性。

    2. 为了保证数据强一致,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索引

    区别就是:

    1. MyISAM 索引文件 和 表记录数据 是单独分开的。由索引最后叶子节点里面主键对应的地址去表记录找。
    2. 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

    相关文章

      网友评论

          本文标题:事务隔离与锁与索引

          本文链接:https://www.haomeiwen.com/subject/rdhywftx.html