MySQL有三种锁的级别:mysql
1)表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的几率最高,并发度最低。 2)行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。 3)页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常。 4)InnoDB行级锁的实现:InnoDB的行级锁是经过在索引上加锁来实现的,因此只有经过明确的索引来查找数据时才会使用行级锁!换句话说就是:若是在执行sql时没有用到索引,则mysql就没法使用行锁了。
MySQL中锁的类型:sql
共享锁(S锁:Shared lock) 1)共享锁又叫读锁,MySQL会在select ... lock in share mode语句的查询结果集上添加共享锁; 2)共享锁能够被多个事务同时持有。 3)某个事务在涉及的数据行加上共享锁后,全部的事务只能对这些数据进行读操做,目的是为了防止在读取数据的过程当中,其它事务对数据进行修改。 4)不能在共享锁的基础上再加其它类型的锁。 独占锁(X锁:Exclusive lock) 1)独占锁又叫排它锁,InnoDB引擎默认会给insert、delete、update、select ... for update 等语句加上独占锁。 2)独占锁只能被一个事务获取,其它事务只有等到持有独占锁的事务将锁释放后,才能去获取独占锁。 3)某个事务在涉及的数据行加上独占锁后,这个事务就能够对锁定这些数据进行修改操做了。 4)不能在独占锁的基础上再加其它类型的锁。 共享锁和独占锁能够加在表、页、数据行(索引)上。 排它锁的选择: 若where条件中明确指定了主键,且该行数据存在,则只锁定该行,故排它锁为行锁(row lock)。 若where条件中明确指定了主键,可是该行数据不存在,则不会加锁。 若where条件中明确指定了索引,且该行数据存在,则只锁定该行,故排它锁为行锁(row lock)。 若where条件中明确指定了索引,可是该行数据不存在,则不会加锁。 若where条件中未明确指定主键或索引,则会锁定全表,故排它锁为表锁(table lock)。换句话说就是:在执行sql时没有用到索引!!! 注:未明确指定 即 未指定(主键/索引) 或 指定的是(主键/索引)的范围 eg: # 只锁定message_id为1的行 set autocommit=0; begin; select * from t_message where message_id=1 for update; # message_id为主键 commit; # 锁定全表 set autocommit=0; begin; select * from t_message where message_id>1 for update; # message_id为主键 commit; # 锁定全表 set autocommit=0; begin; select * from t_message where type='good' for update; # good非索引列 commit; 其它线程由于等待(排它锁)超时而报错: update t_message set title='asdf' where message_id=1; [Err] 1205 - Lock wait timeout exceeded; try restarting transaction
死锁产生的四个必要条件:数据库
互斥条件 资源只能由一个线程使用 请求保持 保持已锁定的资源不释放 不可剥夺 已持有的资源不会被其它线程剥夺 环路条件 循环等待
避免死锁:并发
说明:致使死锁的常见场景:两个Connection中加锁的顺序不一致。 1)不一样的方法并发存取多个表时,尽可能以相同的顺序访问这些表。 2)在一个事务中,尽可能一次性锁定所需的全部资源,即一次性锁定多行。
排查死锁:spa
1)show processlist 运行时间最大的(即:Time值最大)的线程最有多是致使死锁的线程。 2)MySQL中information_schema数据库中关于Innodb事务和锁的三张表: select * from information_schema.INNODB_TRX select * from information_schema.INNODB_LOCKS select * from information_schema.INNODB_LOCK_WAITS 3)show engine innodb status 4)kill MySQL线程Id
Tips: 在select后面添加sleep(n)后,该sql最少会执行n秒;若查询结果为m行,则该sql最少会执行m*n秒。 eg:select sleep(5),t.name from t_user t where t.age=1线程
MySQL中information_schema数据库中关于Innodb事务和锁的三张表:rest
1)查看在InnoDB引擎中正在执行的事务,包括:正在执行的事务 和 因申请加锁而等待的事务。 SQL:select * from information_schema.INNODB_TRX trx_id 事务的ID trx_state 事务的状态: RUNNING, LOCK WAIT, ROLLING BACK or COMMITTING. trx_started 事务的开始时间 trx_requested_lock_id 事务等待的锁的ID(若是事务状态不是LOCK WAIT,这个字段是NULL),详细的锁的信息能够连查INNODB_LOCKS表 trx_wait_started 事务等待开始的时间(若是事务状态不是LOCK WAIT,这个字段是NULL) trx_weight 事务的权重,反映了一个事务修改和锁住的行数。当发生死锁回滚的时候,优先选择该值最小的进行回滚。 trx_mysql_thread_id MySQL中的线程ID,show processlist结果中的Id列。 trx_query 事务中正在运行的sql语句 trx_operation_state 事务当操做的类型 trx_tables_in_use 查询用到的表的数量 trx_tables_locked 查询加行锁的表的数量 2)查看在InnoDB引擎中存在的锁,包括:事务正在申请的锁 和 事务已经持有的锁。 SQL:select * from information_schema.INNODB_LOCKS lock_id 锁ID lock_trx_id 事务ID,能够连INNODB_TRX表查事务详情 lock_mode 锁的模式: S, X, IS, IX, S_GAP, X_GAP, IS_GAP, IX_GAP, or AUTO_INC lock_type 锁的类型:行级锁 或 表级锁 lock_table 加锁的表 lock_index 若是是lock_type='RECORD' 行级锁,为锁住的索引,若是是表锁为null lock_space 若是是lock_type='RECORD' 行级锁,为锁住对象的Tablespace ID,若是是表锁为null lock_page 若是是lock_type='RECORD' 行级锁,为锁住页号,若是是表锁为null lock_rec 若是是lock_type='RECORD' 行级锁,为锁住行号,若是是表锁为null lock_data 事务锁住的主键值,如果表锁,则该值为null 3)查看在InnoDB引擎中锁等待的相关信息: SQL:select * from information_schema.INNODB_LOCK_WAITS requesting_trx_id 申请锁的事务ID requesting_lock_id 申请的锁的ID blocking_trx_id 阻塞的事务ID blocking_lock_id 阻塞的锁的ID
show open tables where in_use > 0 Database 数据库 Table 表名 In_use 正在访问该表的线程数 Name_locked 表名是否被锁(Drop或Rename这张表时,表名会被锁住)code