mysql锁分类

数据库中的锁一般都是自动加的

mysql锁主要分为两大类:

  1. 悲观锁
    按作用性质分
  1. 读锁(共享锁、S锁)

事务A在读取一个记录a时,会先回去该记录的读锁,之后其他事务可以获取该记录的读锁并读取,但是不能修改。

如果事务A需要对记录a进行修改,那么需要将读锁升级为写锁。升级为写锁的条件是该记录没有其他读锁,因此

如果有两个事务同时想对同一个记录的读锁升级为写锁,就会发生死锁问题

  1. 主动加锁

select name from user where id = 1 lock in share mode; -- 或者 select name from user where id = 1 with (holdlock)

  1. 写锁(互斥锁,X锁,排它锁、独占锁)

一个事务对一个记录加了写锁之后其他事务不能读写该记录,会一直阻塞,直到该事务释放锁

  1. 主动加锁

select name from user where id = 1 for update;

  1. 更新锁(U锁)

这个锁是为了防止读锁升级的死锁问题,用于预定将要对一个记录进行写操作,一个事务对一个记录加了更新锁之后,其他事务可以读,但是不能再添加更新锁或者读锁。

  1. 主动加锁

select name from user where id = 1 with (updlock)

  1. 自旋锁

自旋锁与写锁类似每次只有一个事务可以获取锁,不同的是使用了自旋锁,等待锁的事务会循环尝试获取锁,比写锁效率高,但是也消耗cpu资源,自旋锁有个自旋等待最大时间,当其他事务自旋超过了最大自选等待时间还是没有释放锁时,自旋线程就会进入阻塞状态。自旋锁在递归调用时会发生死锁现象

  1. 按锁的粒度分
  1. 行锁(InnoDB引擎)

粒度最细的一种锁,只对当前操作的行加锁,发生锁冲突的概率最小,因为范围很小,但是加锁解锁次数多,加锁慢,对资源消耗较大,但是并发度也最高

  1. 间隙锁

间隙锁是对一个区间的数据进行加锁,该区间为左闭右开区间,被加了间隙锁的区间的数据不可新增和删除,即使该数据不存在。间隙锁+行锁为next-key lock,间隙锁是在事务隔离级别为可重复读时才会产生,在InnoDB的可重复读中隔离级别中解决了幻读问题就是靠间隙锁,因为加了间隙锁之后区间内不可新增和减少数据。

  1. 表锁(MyISAM引擎)

对整个表加锁,发生冲突概率大,并发度低,加锁快

  1. 页锁(BDB引擎)

一次锁定相邻的一组记录,并发度、加锁速度、冲突概率介于行锁与表锁之间

  1. 乐观锁

乐观锁是一种思想,并不需要借助数据库的锁机制。乐观锁一般有两种实现方式:

1.一种是借助版本号

在读取时获取一次版本号,版本号每更新一次数据就递增一次,在更新之前对比数据版本号,如果版本要等于之前读的版本号

就可以进行更新,否则失败;

2.一种是根据原本数据值

和版本方式类似,在读取时获取原本数据值,更新时对比是否和原值相等

使用乐观锁需要注意判断版本号或值与更新操作应该是原子的,否则判断完再去更新,在这期间可能数据会被改动