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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
-多个线程的几种实现方式包括:承Thread类,实现Runnable接口,实Callable接口,使用线程池。 - Java中的线程池是通过ThreadPoolExecutor类实现的。线程池维护了一个线程队列,可以复用线程,减少线程的创建和销毁开销,提高了性能。 - 不建议直接使用Executors工具类创建线程池是因为它使用的是默认的线程池配置,可能导致线程数量过多,耗尽系统资源。OOM(Out of Memory)是由于创建过多的线程导致内存不足而发生的错误。 - Java内存模型(JMM)是一种规范,定义了多线程程序中各个变量的访问方式。它包括主内存和工作内存,通过控制变量的可见性和原子性来保证线程间的通信与同步。 - 并发编程可能会发生的问题包括:竞态条件、死锁、活锁、饥饿等。可见性问题指一个线程对共享变量的修改对其他线程是否可见,原子性问题指一个操作是否可以被中断或者同时执行。 - 并发编程下会出现原子性问题是因为多个线程同时修改同一个共享变量时,可能会导致不一致的结果。有序性问题是指程序执行的顺序与预期不符。可以使用synchronized关键字、Lock锁等来解决原子性和有序性问题。加上volatile关键字可以保证可见性,禁止指令重排序。 - 内存屏障是通过编译器和处理器来实现的,用于控制指令的执行顺序和内存的可见性。synchronized关键字会在进入和退出临界区时加上内存屏障。 - 单线程指令重排在不影响单线程执行结果的前提下进行优化,但可能会影响多线程的正确性。双重校验锁中使用volatile是为了禁止指令重排,确保多线程环境下的正确性。 - InnoDB的索引是通过B+树实现的。B+树具有树高度低、查询效率高、支持范围查询等优势。 - 聚簇索引与非聚簇索引的区别在于数据的存储方式。聚簇索引将数据行存储在叶子节点中,非聚簇索引则将叶子节点指向数据行。不是所有情况都需要取回表的数据,可以通过覆盖索引来避免回表操作。 - 最左前缀匹配指在使用联合索引时,只有从左到右使用索引的前缀部分才能发挥索引的作用。将区分度高的字段放在最左边可以提高索引的效率。唯一索引与普通索引的区别在于是否允许重复值。 - 排查慢SQL可以通过查看慢查询日志、使用性能分析工具(如EXPLAIN、SHOW PROFILE)、优化查询语句等方法。 - MySQL的锁包括行锁表锁行锁在并发性能上更好,但需要更多的系统资源,适合处理并发访问较高的场景。表锁在资源消耗上较少,但并发性能相对较差,适合处理并发访问较低的场景。 - FOR UPDATE语句会对查询到的行加上行锁。 - 悲观锁是指在操作数据时始终假设会发生并发冲突,因此会将数据加锁以阻止其他事务的访问。乐观锁是指不加锁,而是通过版本号或时间戳等机制来判断是否发生冲突,减少了加锁的开销。悲观锁适用于并发冲突较多的场景,乐观锁适用于并发冲突较少的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值