美文网首页
《MysSQL自学笔记》之锁

《MysSQL自学笔记》之锁

作者: 夏天嘚花花 | 来源:发表于2019-01-18 16:20 被阅读0次

    数据库锁

    image.png
    • 表锁:开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
    • 行锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
    • InnoDB行锁和表锁都支持!InnoDB只有通过索引条件检索数据才使用行级锁
    • MyISAM只支持表锁!

    MyISAM表级锁

    MySQL 的表级锁有两种模式:表共享读锁表独占写锁
    读读不阻塞,读写阻塞,写写阻塞
    读锁和写锁是互斥的,读写操作是串行
    对 MyISAM 表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;对 MyISAM 表的写操作,则会阻塞其他用户对同一表的读和写操作。当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。

    session_1 session_2
    获得text表的锁定:
    mysql> lock table text write;
    当前 session 对text表的查询、更新、插入操作都可以执行 session2对于text表的查询、更新、插入操作都得阻塞等待
    释放锁:
    unlock tables;
    等待
    session_2的操作得到执行
    如何给MyISAM加表锁

    MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用 LOCK TABLE 命令给 MyISAM 表显式加锁。
    但有些特殊需求下需要我们手动加表锁。举个例子:例如订单表记录了订单的总金额,订单详细表记录了订单中各个商品的价格,现在需要比对订单总金额跟订单详细表金额的总价是否正确。

    select sum(total) from orders;
    select sum(subtotal) from order_detail;
    比对 toatal 和 total_deail
    

    这时候就需要手动将order,order_detail手动加锁,不然查询时又有新的记录插入会导致比对不一致。

    Lock tables orders read local, order_detail read local;
    Select sum(total) from orders;
    Select sum(subtotal) from order_detail;
    Unlock tables;
    

    注意点:

    • 在执行 LOCK TABLES 后,只能访问显式加锁的这些表,不能访问未加锁的表
    • 如果加的是读锁,那么只能执行查询操作,而不能执行更新操作
    • 写锁和读锁优先级的问题是可以通过参数调节的:max_write_lock_count和low-priority-updates
    • MyISAM可以支持查询和插入操作的并发进行。可以通过系统变量concurrent_insert来指定哪种模式,在MyISAM中它默认是:如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。
    MyISAM 的锁调度

    MyISAM 存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么,一个进程请求某个 MyISAM 表的读锁,同时另一个进程也请求同一表的写锁,MySQL 如何处理呢?
    写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前

    Innodb行锁

    InnoDB实现了以下两种类型的行锁

    • 共享锁(S锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁
      (也叫做读锁:读锁是共享的,多个客户可以同时读取同一个资源,但不允许其他客户修改)
    • 排他锁(X锁) :允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁
      (也叫做写锁:写锁是排他的,写锁会阻塞其他的写锁和读锁)

    另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB 还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁

    • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁
    • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁


      image.png

    意向锁是 InnoDB 自动加的,不需用户干预。对于 UPDATE、DELETE 和 INSERT 语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通 SELECT 语句,InnoDB 不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁:

    • 共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
    • 排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE

    只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁

    session1 session2
    mysql> select * from tab_no_index where id = 1 for update;
    mysql> select * from tab_no_index where id = 2 for update;
    阻塞等待

    这里由于tab_on_index表没有加索引,所以即使是为id=1的加锁,也是用到的不是行锁而是表锁,所以导致session2查询时阻塞等待

    由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。

    当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁

    间隙锁

    当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB 也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key 锁)。

    相关文章

      网友评论

          本文标题:《MysSQL自学笔记》之锁

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