关于Mysql数据库,这些知识点你确定都会了吗?( 三 )


页级锁
资源开销介于行级锁和表级锁 , 会出现死锁 。
行级锁
每个事务仅会锁住被影响的行 , 也就是说 , 涉及到哪些行记录 , 哪些行才会被锁住 , 会出现死锁 。优点是锁冲突概率小 , 并发度高 。缺点是由于锁离子度小 , 加锁和释放锁的次数大大增加 , 资源开销大 。
mysql的行级锁通过索引项上的索引来实现的 , innodb这种行锁实现特点意味着只有通过索引条件检索数据 , innodb才会使用行级锁 , 否则 , innodb将使用表锁 。
间隙锁(Next-Key锁)
当我们用范围条件而不是相等条件检索数据 , 并请求共享锁或排他锁时 , innodb会给符合条件的已有数据的索引项加锁;对于键值在条件范围内但并不存在的记录 , 叫做间隙 , innodb也会对这个间隙加锁 , 这种锁机制不是所谓的间隙锁 。InnoDb使用间隙锁的目的 , 一方面是为了防止幻读 , 以满足相关隔离级别的要求 , 对于上面的例子 , 要是不使用间隙锁 , 如果其它事务插入更改了任何记录 , 那么本事务再次执行上述语句 , 就会发生幻读;另一方面 , 是为了满足其恢复和复制的需要 , 有关恢复和复制机制的影响 , 以及不同隔离级别下innodb使用间隙锁的情况 。
很显然 , 在使用范围条件检索并锁定记录时 , innodb对这种加锁机制会阻塞符合条件范围内键值的并发插入 , 这往往会造成严重的锁等待 。因此 , 在实际开发中 , 尤其是并发插入比较多的应用 , 我们尽量优化业务逻辑 , 尽量使用相等条件来访问更新数据 , 避免使用范围条件 。
死锁
死锁是指两个或多个事务在同一个资源上相互占用 , 并请求锁定对方占用的资源 , 从而导致恶性循环 。当事务试图以不同的顺序锁定资源时 , 就可能产生死锁 。多个事务同时锁定同一个资源时也可能产生死锁 。
innodb避免死锁

  1. 为了在单个innodb表上执行多个并发写入操作时避免死锁 , 可以在事务开始时通过为预期要修改的每个记录(行) 使用SELECT ... FOR UPDATE 语句来获取必要的锁 , 即使这些行的更改语句是在之后才执行的 。
  2. 在事务中 , 如果要更新记录 , 应该直接申请足够级别的锁 , 即排他锁 , 而不应先申请共享锁、更新时再申请排他锁 , 因为这时候当用户在申请排他锁时 , 其它事务可能又已经获取了相同记录的共享锁 , 从而造成锁冲突 , 甚至死锁
  3. 如果事务需要修改或锁定多个表 , 则应在每个事务中以相同的顺序使用加锁语句 。在应用中 , 如果不同的程序会并发存取多个表 , 应尽量约定以相同的顺序来访问表 , 这样可以大大降低死锁的机会
  4. 同过SELECT...LOCK IN SHARE MODE 获取行的读锁后 , 如果当前事务再需要对该记录进行更新操作 , 则很可能造成死锁 。
  5. 改变事务隔离级别
如果出现死锁 , 可以使用SHOW INNODB STATUS 命令来确定最后一个死锁产生的原因 。返回结果中包括死锁相关事务的详细信息 。如引发的SQL语句 , 事务已经获得的锁 , 正在等待什么锁 , 以及被回滚的事务等 。据此可以分析死锁产生的原因和改进措施 。
乐观锁
加锁是为了占用资源 , 我们上面说过加锁和释放锁都会有资源开销 。在有些不需要加锁就能获取资源岂不是更好?乐观锁是乐观的认为在抢占资源是不用加锁就能获取资源(因为没有其它事务抢占资源或者发生的冲突概率小 , 稍稍尝试几次就能成功 , 美滋滋) 。适用冲突概率小的情景下 。
悲观锁
在冲突概率大的情况下 , 悲观的认为抢不到资源或者多次都抢不到资源 。只能通过加锁的方式抢占资源 , 然后再做处理 , 最后释放资源 。
SQL优化优化必备的explain命令
explain命令是用来查询SQL的执行计划 用法:explain select filed from table;
会查询出以下重要字段:
+----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+ | id | selecttype | table | partitions | type | possiblekeys | key | keylen | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | t0 | NULL | range | idxtradeid | idxtrade_id | 8 | NULL | 2 | 100.00 | Using index condition | +----+-------------+-------+------------+-------+---------------+--------------+---------+------+------+----------+-----------------------+ 1 row in set (0.02 sec)


推荐阅读