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,可以看到这里是行锁。

mysql悲观锁是行锁还是表锁?_第1张图片

示例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,数据库,sql)