InnoDB支持行级锁和表级锁(默认行级锁),支持事务,外部键等;大量的insert和update更快等。只有经过索引条件检索数据,InnoDB 才使用行级锁,不然,InnoDB 将使用表锁。mysql
MyISAM是表级锁,不支持事务,大量的SELECT查询更快等sql
BDB引擎支持页级锁和表级锁(默认页级锁)数据库
行级锁是 MySQL 中锁定粒度最细的一种锁,表示只针对当前操做的行进行加锁。行级锁能大大减小数据库操做的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。并发
特色性能
开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。spa
表级锁是 MySQL 中锁定粒度最大的一种锁,表示对当前操做的整张表加锁,它实现简单,资源消耗较少,被大部分 MySQL 引擎支持。最常使用的 MyISAM 与 InnoDB 都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。线程
特色设计
开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的几率最高,并发度最低。code
页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以,采起了折衷的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。orm
特色
开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常。
前面提到过,在 InnoDB 引擎中既支持行锁也支持表锁,那么何时会锁住整张表?何时只锁住一行呢?
InnoDB 行锁是经过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不一样,后者是经过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现的特色意味着:只有经过索引条件检索数据,InnoDB 才使用行级锁,不然,InnoDB 将使用表锁。
在实际应用中,要特别注意 InnoDB 行锁的这一特性,否则的话,可能致使大量的锁冲突,从而影响并发性能。
MyISAM 中是不会产生死锁的,由于 MyISAM 老是一次性得到所需的所有锁,要么所有知足,要么所有等待。而在 InnoDB 中,锁是逐步得到的,就形成了死锁的可能。
在 MySQL 中,行级锁并非直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,若是一条 SQL 语句操做了主键索引,MySQL 就会锁定这条主键索引;若是一条 SQL 语句操做了非主键索引,MySQL 就会先锁定该非主键索引,再锁定相关的主键索引。 在进行UPDATE
、DELETE
操做时,MySQL 不只锁定WHERE
条件扫描过的全部索引记录,并且会锁定相邻的键值,即所谓的next-key locking
.
当两个事务同时执行,一个锁住了主键索引,在等待其余相关索引;另外一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。
发生死锁后,InnoDB 通常均可以检测到,并使一个事务释放锁回退,另外一个获取锁完成事务。
有多种方法能够避免死锁,这里只介绍常见的三种:
死锁的解决方案:
一、先查看当前库的线程状况:show full processlist; 目的看先有没有这在执行的慢sql线程,若是有就kill掉
二、若是没有,再去查看innodb的事务表INNODB_TRX,看下里面是否有正在锁定的事务线程,看看ID是否在show full processlist里面的sleep线程中,若是是,就证实这个sleep的线程事务一直没有commit或者rollback而是卡住了
SELECT * FROM information_schema.INNODB_TRX G;若是有就kill掉
共享锁和排他锁:
一、共享锁:称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据能够共享一把锁,都能访问到数据,可是只能读不能修改。
二、排他锁:又称为写锁,简称X锁,顾名思义,排他锁就是不能与其余所并存,如一个事务获取了一个数据行的排他锁,其余事务就不能再获取该行的其余锁,包括共享锁和排他锁,可是获取排他锁的事务是能够对数据就行读取和修改。
对于共享锁你们可能很好理解,就是多个事务只能读数据不能改数据,对于排他锁你们的理解可能就有些差异,我当初就犯了一个错误,觉得排他锁锁住一行数据后,其余事务就不能读取和修改该行数据,其实不是这样的。排他锁指的是一个事务在一行数据加上排他锁后,其余事务不能再在其上加其余的锁。mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,若是加排他锁可使用select ...for update语句,加共享锁可使用select ... lock in share mode语句。因此加过排他锁的数据行在其余事务种是不能修改数据的,也不能经过for update和lock in share mode锁的方式查询数据,但能够直接经过select ...from...查询数据,由于普通查询没有任何锁机制。
注意:mysql的update、delete、insert是默认加了排他锁的,而普通的selete是什么锁都没加,因此普通selete既能查共享锁的行也能查排他锁的行