zoukankan      html  css  js  c++  java
  • 关于MYSQL中的锁

    根据mysql存储引擎的不同,支持的锁也不同。

    myisam,memory,支持表级锁。

    innodb,支持行级锁和表级锁,默认为行级锁。

    表级锁,把整个表锁住。锁表快。不存在死锁。冲突多。

    行级锁,锁指定的行。锁表慢。可能出现死锁。冲突少。

    关于死锁:

    表中有2条数据X,Y。有两个人都想修改这两个数据。并且A先修改X,然后修改Y。B先修改Y,然后修改X。

    这两个人同时执行这个事情。

    表级锁:无论A先执行还是B先执行,都会先把表锁了,另一个人只能等待,知道第一个人操作完成。所以数据是肯定安全的。

    行级锁:会同时开启事务,A修改了X,B修改了Y。这时A想要修改Y,但是B想要修改X,但是他们都在占用这对方想要操作的数据,死锁就产生了。我也只能想到让他们按照顺序执行能避免死锁。

    表级锁:

    表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)

    一个线程执行一个检索SQL,涉及到的所有表都被加上共享读锁,别的线程只能去读这些表。

    一个线程执行一个增删改SQL,涉及到的表会被加上独占写锁,别的线程去读这个表或者修改这个表都需要等待前面的线程结束。

    表级锁加锁是不需要人为控制的。当执行SQL检索时会被自动加上读锁。当执行增删改SQL时,会自动加上写锁。

    行级锁:

    共享锁:行锁。

    排他锁:行锁。

    意向共享锁:表锁。

    意向拍他锁:表锁。

    可以给一个有共享锁的行再加一个共享锁或意向共享锁。但是不能给一个有共享锁的行加一个拍他锁或意向拍他锁。

    一行数据上有一个拍他锁的话,不能给这行数据加任意锁。只能等待直到该锁被释放。

    请求锁模式
       是否兼容
    当前锁模式
    X IX S IS
    X 冲突 冲突 冲突 冲突
    IX 冲突 兼容 冲突 兼容
    S 冲突 冲突 兼容 兼容
    IS 冲突 兼容 兼容 兼容

    如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。
    意向锁是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

    用SELECT ... IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。
    但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT... FOR UPDATE方式获得排他锁。
    2.InnoDB行锁实现方式
    InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
    在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。下面通过一些实际例子来加以说明。
    (1)在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。
    (2)由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
    (3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
    (4)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
    3.间隙锁(Next-Key锁)
    当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;
    对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
    例:
    假如emp表中只有101条记录,其empid的值分别是 1,2,...,100,101,下面的SQL:

    mysql> select * from emp where empid > 100 for update;

    是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
    InnoDB使用间隙锁的目的:
    (1)防止幻读,以满足相关隔离级别的要求。对于上面的例子,要是不使用间隙锁,如果其他事务插入了empid大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读;
    (2)为了满足其恢复和复制的需要。
    很显然,在使用范围条件检索并锁定记录时,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。
    除了间隙锁给InnoDB带来性能的负面影响之外,通过索引实现锁定的方式还存在其他几个较大的性能隐患:
    (1)当Query无法利用索引的时候,InnoDB会放弃使用行级别锁定而改用表级别的锁定,造成并发性能的降低;
    (2)当Query使用的索引并不包含所有过滤条件的时候,数据检索使用到的索引键所只想的数据可能有部分并不属于该Query的结果集的行列,但是也会被锁定,因为间隙锁锁定的是一个范围,而不是具体的索引键;
    (3)当Query在使用索引定位数据的时候,如果使用的索引键一样但访问的数据行不同的时候(索引只是过滤条件的一部分),一样会被锁定。
    因此,在实际应用开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。
    还要特别说明的是,InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁。

     

  • 相关阅读:
    django-替代为自定义的User model
    python *args 和 ** kwargs
    MySQL:性能优化
    MySQL:常用的数据模型
    MySQL:存储过程和函数
    MySQL:用户管理
    MySQL:索引
    MySQL:基础知识
    Linux:NFS配置
    Linux:Apache安装与启动
  • 原文地址:https://www.cnblogs.com/voctrals/p/7614836.html
Copyright © 2011-2022 走看看