Go微服务: 悲观锁

2024-06-12 02:20
文章标签 服务 go 悲观

本文主要是介绍Go微服务: 悲观锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

悲观锁概述

  • 悲观锁,作为并发控制领域的重要概念,广泛应用于数据库管理系统、多线程编程以及其他需要协调资源访问的场景中
  • 悲观锁(Pessimistic Lock),顾名思义,基于一种“悲观”的假设,即认为在数据处理过程中,很可能会发生并发冲突
  • 因此提前对数据加锁,以防止其他事务或线程的并发修改
  • 这种机制牺牲了一定的并发性能,以换取数据的一致性和安全性
  • 悲观锁的核心思想在于“先获取锁,再操作”
  • 在获取锁的过程中,如果资源已被其他进程锁定,则当前进程必须等待锁释放
  • 具体实现时,数据库系统或并发编程框架会提供相应的API来实现锁的获取与释放
  • 一旦获得锁,持有锁的进程便可以独占访问资源,直到显式释放锁或事务结束

锁的粒度, 类型, 应用场景


1 ) 粒度

  • 悲观锁的粒度可粗可细,从表级锁到行级锁不等,其中:
    • 表级锁:锁定整个表,适用于并发访问较少的场景,但会导致严重的性能瓶颈
    • 行级锁:锁定数据表中的某一行或几行数据,大大提高了并发处理能力,是大多数数据库系统推荐的锁策略

2 )类型

  • 常见的悲观锁类型包括:
    • 共享锁(Shared Locks)
      • 允许多个事务读取同一资源,但任何事务都不能修改
    • 排他锁(Exclusive Locks)
      • 独占资源,不允许其他事务读取或修改,常用于写操作

3 )应用场景

  • 写密集型操作:当系统中有大量写操作,且写操作间冲突频繁时,悲观锁能够有效避免并发写导致的数据不一致
  • 重要数据保护:对于一些敏感或关键数据,优先保证数据的完整性和一致性比追求高并发更为重要

悲观锁在mysql中的应用

  • 实际上默认每次运行 sql 都会 自动 commit,我们来看下
    • $ select @@autocommit; 这里得到的结果默认是 1
    • $ set autocommit=0; 现在设置为 0 不让自动提交
  • 现在比如有一个 stock 的表
    • $ select * from stock; 假设正常来说查询到一条记录
  • mysql 使用 for update 来实现悲观锁
  • 现在开2个mysql的客户端

1 )客户端1

  • 现在查询一条数据
  • $ select * from stock where id=1 where id = 1 for update;
  • 可见能够正常查询出来,这里用到了 for update

2 )客户端2

  • 在客户端2中进行查询
  • $ select * from stock where id=1 where id = 1 for update;
  • 这时候迟迟不返回,阻塞了
  • 现在回到 客户端1 执行 $ commit;
  • 可以看到,客户端2 从阻塞的状态立即拿到结果了
  • 还有需要注意的是:
    • 如果客户端1一直不提交,mysql有个超时机制
    • 超时之后,也不会再阻塞
    • 一般不考虑这种情况

3 ) 所以

  • 这个mysql中的for update 就类似 go语言 里的排他锁
  • mysql 的这个 for update 锁,没有锁住其他 id 的记录
  • 也就是说 上面示例中的 for update 是一个行级锁,只锁定了一条记录
  • 但是,要满足一些条件的时候才是行级锁,只有查询的是索引字段才是行级锁
  • 如果没有索引,那么它会把行级锁变成表锁,这个事情就严重了
  • 这个性能就是非常可怕,断崖式下跌,比如现在查询 num, 这里num是非索引
    • 在客户端1, $ select * from stock where num=1 for update;
    • 在客户端2,$ select * from stock where num=10 for update;
    • 这里如果是行级锁就不会阻塞,但是这里阻塞了, 也就是说这里变成了表锁
  • 所以,非索引 for update 是一个非常恐怖的事情,性能断崖式下跌
  • 悲观锁,在行级锁的情况下,在某些非高并发的场景下,其实还是可以接受的

悲观锁在GORM中的应用

  • 文档
    • https://gorm.io/zh_CN/docs/advanced_query.html#锁
    • https://www.kancloud.cn/sliver_horn/gorm/1861159

总结

  • 悲观锁是一种重要的并发控制手段,它通过预先锁定资源,有效避免了并发修改引发的数据不一致性问题
  • 尽管悲观锁在高并发环境下可能会影响性能,但在处理敏感数据或写密集型操作时,其提供的严格数据保护机制显得尤为关键
  • 开发者在选择使用悲观锁时,应充分评估系统的并发需求、数据敏感度以及性能指标,合理权衡悲观锁与乐观锁的应用场景,以达到最佳的并发控制效果

这篇关于Go微服务: 悲观锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1052927

相关文章

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

GO语言实现串口简单通讯

《GO语言实现串口简单通讯》本文分享了使用Go语言进行串口通讯的实践过程,详细介绍了串口配置、数据发送与接收的代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录背景串口通讯代码代码块分解解析完整代码运行结果背景最近再学习 go 语言,在某宝用5块钱买了个

MyBatisPlus乐观锁和悲观锁的实现示例

《MyBatisPlus乐观锁和悲观锁的实现示例》本文主要介绍了MyBatisPlus乐观锁和悲观锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录1.场景2.乐观锁和悲观锁3.乐观锁实现4.悲观锁1.场景一件商品,成本价是80元,售价是10

nacos服务无法注册到nacos服务中心问题及解决

《nacos服务无法注册到nacos服务中心问题及解决》本文详细描述了在Linux服务器上使用Tomcat启动Java程序时,服务无法注册到Nacos的排查过程,通过一系列排查步骤,发现问题出在Tom... 目录简介依赖异常情况排查断点调试原因解决NacosRegisterOnWar结果总结简介1、程序在

Go 使用环境变量的实现小结

《Go使用环境变量的实现小结》作为软件开发人员,在项目中管理配置变量的重要性,本文主要介绍在Golang中处理环境变量的强大工具github.com/joho/godotenv包,利用这个包,你可以... 目录步js骤 1:安装步骤 2:制作 .env 文件步骤android 3:加载环境变量步骤 4:利用

GO语言zap日志库理解和使用方法示例

《GO语言zap日志库理解和使用方法示例》Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,:本文主要介绍GO语言zap日志库理解和使用方法的相关资... 目录1. zap日志库介绍2.安装zap库3.配置日志记录器3.1 Logger3.2 Sugared

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql