封锁就是事务在对某个数据操作之前,先向系统发出请求对其加锁。在它释放锁之前,其他事务不能更新此数据。
数据库中的锁按不同特性有不同的分类方案:

1、说一下 MySQL 的行锁和表锁?各自有哪些例子?
MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。
- 表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
- 行级锁:开销大,加锁慢,会出现死锁。锁粒度小,发生锁冲突的概率小,并发度最高。
InnoDB什么时候触发表锁,什么时候触发行锁?
答:只有「明确的」用到了索引,才会触发行锁,否则是表锁。
-
有些情况数据库引擎会放弃索引进行全表扫描,比如模糊查询、or关键字、where条件中等号的左侧进行表达式或函数操作、where 1=1操作、正则表达式。
-
另外就是如果优化器估计使用全表扫描要比使用索引快,则自动放弃索引。
行锁的例子(按“多个线程可不可以共享同一把锁”来分):
- 共享锁:读取一行时使用,可被多个线程所持有。也就是说支持并发读,但在读锁未释放之前,不能对数据进行写操作。
- 排他锁:更新一行时使用,该锁一次只能被一个线程所持有。当一个线程获得写锁后,他既可以读也可以写,其他线程既不能读也不能写。
- 间隙锁:范围条件时使用。锁定一个范围,不包括记录本身。对范围内不存在的记录加锁,防止幻影行插入
表锁的例子:
- 意向排他锁:准备给数据加排他锁,需要先获得意向排他锁。
- 意向共享锁:准备给数据加共享锁,需要先获得意向共享锁。
2、说一下对悲观锁和乐观锁的理解
先说概念。对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。Java中,synchronized关键字和Lock的实现类都是悲观锁。优点是安全,缺点就是有性能消耗,并且对于长事务来讲,可能会严重影响系统的并发处理能力。适合用在更新频率高查询频率低的场景。因为更新操作易出现问题。
而乐观锁认为自己在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。乐观锁适用于 读多写少 的应用场景,这样可以提高吞吐量。
乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。
自旋锁(CAS算法)思路:线程1对某个数据加锁后,线程2访问时不是阻塞等待,而是循环等待,并且没有时间间隔,持续访问,一被解锁立马就能感知到,效率很高。