mysql悲观锁是行锁还是表锁?

Posted 我爱看明朝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql悲观锁是行锁还是表锁?相关的知识,希望对你有一定的参考价值。

mysql悲观锁是行锁还是表锁?

结论

悲观锁在非主键、非索引时是表锁,在主键、索引时是行锁。

使用悲观锁

在查询语句后面加上 for update 开启悲观锁。

select * from table where col = xx for update;

悲观锁: 在事务执行开始加锁,此时其他事务无法读写,等待事务完成,其他事务才可以获得这个锁。

验证悲观锁

  1. 关闭自动提交 set @@autocommit = 0; (设置事务是手动提交。 0: 手动提交 1: 自动提交,默认)

  2. 确认当前提交方式 select @@autocommit;

  3. 提交事务 commit;

示例验证

表user,id为主键,name没有索引

示例1

事务1
  set @@autocommit = 0; //步骤1
  select * from user where id = 1 for update; // 步骤4
  commit; // 步骤7
事务2
 set @@autocommit = 0; // 步骤2
 select * from user where id = 2 for update; // 步骤5
 commit; // 步骤8
事务3
 set @@autocommit = 0; // 步骤2
 update user set name = '12' where id = 1; //步骤6
 commit; //步骤9

步骤1~9按照顺序执行,我们可以看到:
步骤7没有执行,步骤6会一直等待;步骤5不需要等待步骤7,可以看到这里是行锁。

示例2

事务1
  set @@autocommit = 0; //步骤1
  select * from user where name = '123' for update; // 步骤4
  commit; // 步骤7
事务2
 set @@autocommit = 0; // 步骤2
 select * from user where name = '456' for update; // 步骤5
 commit; // 步骤8
事务3
 set @@autocommit = 0; // 步骤2
 update user set age = 12 where name = '123'; //步骤6
 commit; //步骤9

步骤1~9按照顺序执行,我们可以看到:
步骤7没有执行,步骤5,6会一直等待;和示例1的表现不一样,可以看到是表锁。

再回顾一下结论: 悲观锁在非主键非索引时是表锁,在主键索引时是行锁。

乐观锁

乐观锁: 事务不加锁,不对读写加锁,更新时根据版本号或时间戳判断是否可以更新。

例如表: user, 使用乐观锁,我们新加long型字段version。

 // 伪代码 
 public void update (long id) 
  // 查询
  User user = UserDao.selectbyId(id);
   // 一通业务操作
   do something 
// 更新某个字段
int res = update user set cols = xx, version = verison + 1 where id = xx1 and version = user.version;
 if (res != 1) 
   // 自旋重新执行业务,进行更新
 


我们可以看到乐观锁对比悲观锁,消耗的资源小,不影响其他业务。

两者对比

类型考虑冲突时间优点悲观
悲观锁开始就考虑加锁能够严格保证同步效率低下
乐观锁更新时才考虑效率较高自旋浪费cpu

以上是关于mysql悲观锁是行锁还是表锁?的主要内容,如果未能解决你的问题,请参考以下文章

对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解

对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解

对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解

对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解

对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解 (转)

对mysql乐观锁悲观锁共享锁排它锁行锁表锁概念的理解