关于MySQL锁的详解

有2种
    1、表锁
   2、行锁

支持innodb支持行锁,表级锁
   。myisam只支持表级锁

innodb实现了下面2种标准的行级锁
    。共享锁  S LOCK 允许事务读一行数据
    。排他锁 X LOCK 允许事务删除或更新一行数据
行锁
     行锁的劣势:开销大;加锁慢;会出现死锁
    行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
    加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB    会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何   锁;当然我们也可以显示的加锁:
    共享锁:select * from tableName where ... + lock in share more
    排他锁:select * from tableName where ... + for update 
    InnoDB和MyISAM的最大不同点有两个:一,InnoDB支持事务(transaction);二,默认采用行级锁。加锁可以保证事务的一致性
间隙锁
    说明:当我们用范围条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)"。InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
    危害(坑):若执行的条件是范围过大,则InnoDB会将整个范围内所有的索引键值全部锁定,很容易对性能造成影响。
排他锁
    说明:排他锁,也称写锁,独占锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
共享锁
    说明:共享锁,也称读锁,多用于判断数据是否存在,多个读操作可以同时进行而不会互相影响。当如果事务对读锁进行修改操作,很可能会造成死锁。
行锁优化
    1 尽可能让所有数据检索都通过索引来完成,避免无索引行或索引失效导致行锁升级为表锁。
    2 尽可能避免间隙锁带来的性能下降,减少或使用合理的检索范围。
    3 尽可能减少事务的粒度,比如控制事务大小,而从减少锁定资源量和时间长度,从而减少锁的竞争等,提供性能。
    4 尽可能低级别事务隔离,隔离级别越高,并发的处理能力越低。
死锁
     说明:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
    此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
    由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
    
    解除死锁方式
        第一种
            1.查询是否锁表
                show OPEN TABLES where In_use > 0;
            2.查询进程(如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程)
                show processlist
            3.杀死进程id(就是上面命令的id列)
                kill id
        
        第二种
            1.查看当前的事务
                SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
            2.查看当前锁定的事务
                SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
            3.查看当前等锁的事务
                SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
    
    产生死锁的几个必要条件
         互斥条件:一个资源每次只能被一个进程使用。
        请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
        不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
        循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
    
    最大限度降低死锁
          1.按同一顺序访问对象。
        2.避免事务中的用户交互。
        3.保持事务简短并在一个批处理中。
        4.使用低隔离级别。
        5.使用绑定连接。

 

===============================================================================================

===============================================================================================

乐观锁
    说明:乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
一般做法:
乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号,或者时间戳。 例子1. SELECT data AS old_data, version AS old_version FROM …; 2. 根据获取的数据进行业务操作,得到new_data和new_version 3. UPDATE SET data = new_data, version = new_version WHERE version = old_version 机制:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。 总结:乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能。

 

悲观锁
    特点
        先获取锁,再进行业务操作。
        即悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作。
        所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。
    
    关联
        共享锁和排它锁是悲观锁的不同的实现,它俩都属于悲观锁的范畴。
    
    机制
        悲观锁的实现依靠的是数据库提供的锁机制来实现,例如select * from news where id=12 for update

 

 

===============================================================================================

===============================================================================================

表锁
    表锁的优势:开销小;加锁快;无死锁
    表锁的劣势:锁粒度大,发生锁冲突的概率高,并发处理能力低
    加锁的方式:自动加锁。查询操作(SELECT),会自动给涉及的所有表加读锁,更新操作(UPDATE、DELETE、INSERT),会自动给涉及的表加写锁。也可以显示加锁:
    共享读锁:lock table tableName read;
    独占写锁:lock table tableName write;
    批量解锁:unlock tables;
共享读锁
    说明:对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读操作,但会阻塞对同一表的写操作。只有当读锁释放后,才能执行其他进程的写操作。在锁释放前不能取其他表。
独占写锁
    说明:对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作。在锁释放前不能写其他表。
总结
    表锁,读锁会阻塞写,不会阻塞读。而写锁则会把读写都阻塞。

============================================================================================

============================================================================================

什么场景下用表锁
    简述:InnoDB默认采用行锁,在未使用索引字段查询时升级为表锁。MySQL这样设计并不是给你挖坑。它有自己的设计目的。
  即便你在条件中使用了索引字段,MySQL会根据自身的执行计划,考虑是否使用索引(所以explain命令中会有possible_key 和 key)。
  如果MySQL认为全表扫描效率更高,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。 。第一种情况:全表更新。事务需要更新大部分或全部数据,且表又比较大。若使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间锁等待和更多的锁冲突。
。第二种情况:多表查询。事务涉及多个表,比较复杂的关联查询,很可能引起死锁,造成大量事务回滚。这种情况若能一次性锁定事务涉及的表,从而可以避免死锁、减少数据库因事务回滚带来的开销。

===============================================================================================================

 

这里更完整的总结了下:https://juejin.im/post/5d5923c75188255d8b2d6cab

===============================================================================================================

总结
    1 InnoDB 支持表锁和行锁,使用索引作为检索条件修改数据时采用行锁,否则采用表锁。
    2 InnoDB 自动给修改操作加锁,给查询操作不自动加锁
    3 行锁可能因为未使用索引而升级为表锁,所以除了检查索引是否创建的同时,也需要通过explain执行计划查询索引是否被实际使用。
    4 行锁相对于表锁来说,优势在于高并发场景下表现更突出,毕竟锁的粒度小。
    5 当表的大部分数据需要被修改,或者是多表复杂关联查询时,建议使用表锁优于行锁。
    6 为了保证数据的一致完整性,任何一个数据库都存在锁定机制。锁定机制的优劣直接影响到一个数据库的并发处理能力和性能。

以上内容仅供自己   温故而知新

参考
    https://segmentfault.com/a/1190000012773157#articleHeader0

 

posted @ 2018-10-09 18:11  陈浩宇人呢  阅读(257)  评论(0编辑  收藏  举报