欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

行级锁 表级锁 乐观锁 悲观锁

程序员文章站 2022-06-02 08:21:23
...

目录

行级锁

表级锁

悲观锁

乐观锁

总结:


行级锁

行级锁,一般是指排它锁,即被锁定行不可进行修改,删除,只可以被其他会话select。行级锁之前需要先加表结构共享锁。

  • row-level loking,锁住一行记录。
  • 开销大,加锁慢,会死锁。
  • 锁粒度小,发生所冲突概率小,并发效率高;适合并发写,事务控制。
  • 并不是直接丢记录行加锁,而是对行对应的索引加锁:
  1. 如果sql 语句操作了主键索引,Mysql 就会锁定这条主键索引。
  2. 如果sql语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。
  3. 在InnoDB中,如果SQL语句不涉及索引,则会通过隐藏的聚簇索引来对记录加锁。
  4. 对聚簇索引加锁,实际效果跟表锁一样,因为找到某一条记录就得扫描全表,要扫描全表,就得锁定表。

表级锁

表级锁,一般是指表结构共享锁锁,是不可对该表执行DDL操作,但对DML操作都不限制。

  • table-level locking,锁住整个表。
  • 开销小,加锁快;不会死锁(一次性加载所需的所有表)。
  • 锁粒度大,发生锁冲突概率大,并发效率低。
  • 适合查询

 

表级锁分为5种,限制程度升序排列:

   (1)行共享(row share):与行排他类似,区别是别的事务还可以在此表上加任何排他锁。(除排他(exclusive)外)

   (2)行排他(row exclusive):其他事务依然可以并发地对相同数据表执行查询,插入,更新,删除操作,或对表内数据行加锁的操作,但不能有其他的排他锁(自身是可以的,没发现有什么用)

   (3)共享(share):在表没有被任何DML操作时,多个事务都可加锁,但只有在仅一个事务加锁的情况下只有此事务才能对表更新;当表已经被更新或者指定要更新时(select for update),任何事务都不能加此锁了。

   (4)共享行排他(share row exclusive):在表没有被任何DML操作时,只有一个事务可以加锁,可以更新,书上说别的事务可以使用select for update锁定选中的数据行,可是实验后没被验证。

   (5)排他(exclusive):在表没有被任何DML操作时,只有一个事务可以加锁,可以更新,与共享行排他的区别还没有发现
 

悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

一方:查询语句加 for update;

另一方:查询语句加 for update;

当进行更新语句的时候,另一方不能进行更新操作。

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

更新语句设置版本号,在指定版本中更新数据

一方:update account set money=money-200,version=version+1 where id=1 and version=0;

另一方操作同一个版本号,则不能更新数据

另一方:update account set money=money+200,version=version+1 where id=1 and version=0;

总结:

​如果更新多,查询少,用悲观锁;反之,乐观锁
表级锁,where用的是非主键
行级锁,where用主键一般是id
如果用表级锁,其他客户将不能进行查询操作,因此开发中记得用行级锁
以mysql为例,有索引并且使用了该索引当条件的时候就是行锁,没有索引的时候就是表锁。
innodb 的行锁是在有索引的情况下,没有索引的表是锁定全表的.​