锁机制的定义:计算机协调多个进程或线程并发访问某一资源的机制

加锁虽然能避免事务的冲突,但是加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否已解除、释放锁等 ,都会增加系统的开销。

MySQL的行锁和表锁

表锁

有读锁(共享锁)和写锁(独占锁),存储默认引擎为MyISAM,当一个线程获得对一个表的写锁后,只有持有锁线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。

特点:

  1. 对整张表加锁
  2. 开销小
  3. 加锁快
  4. 无死锁
  5. 锁粒度大,发生锁冲突概率大,并发性低

MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎,因为写锁以后,其它线程不能做任何操作,大量的更新使查询很难得到锁,从而造成永远阻塞。

行锁

默认引擎:InnoDB,注意:InnoDB支持事务,MyISAM不支持事务。

读锁、写锁、意向共享锁、意向排他锁

意向共享锁(IS)
一个事务给一个数据行加共享锁时,必须先获得表的IS锁

意向排它锁(IX)
一个事务给一个数据行加排他锁时,必须先获得该表的IX锁

特点:

  1. 对一行数据加锁
  2. 开销大
  3. 加锁慢
  4. 会出现死锁
  5. 锁粒度小,发生锁冲突概率最低,并发性高

事务并发的问题:

  1. 更新丢失
    解决:让事务变成串行操作,而不是并发的操作,即对每个事务开始—对读取记录加排他锁
  2. 脏读
    解决:隔离级别为Read uncommitted
  3. 不可重读
    解决:使用Next-Key Lock算法来避免
  4. 幻读
    解决:间隙锁(Gap Lock)

页锁

开销、加锁时间和锁粒度介于表锁和行锁之间,会出现死锁,并发处理能力一般(此锁不做多介绍)

隐式上锁

select //表锁上读锁,行锁不上锁

insert、update、delete //上写锁

显式上锁

lock table tableName read;//读锁
lock table tableName write;//写锁

select * from tableName lock in share mode;//读锁
select * from tableName for update;//写锁

死锁产生条件

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程已获得的资源,在没有使用完之前,不能强行剥夺
  4. 循环等待条件:多个进程之间形成的一种互相循环等待的资源的关系

如何避免死锁

(1)死锁预防:通过确保死锁的一个必要条件不会满足,保证不会发生死锁。

(2)死锁检测:设置检测算法。

(3)死锁避免:银行家算法分配资源。如果一个进程的请求会导致死锁,则不启动该进程。

(4)死锁解除:资源剥夺法、进程撤销法。