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

相关文章

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go中select多路复用的实现示例

《Go中select多路复用的实现示例》Go的select用于多通道通信,实现多路复用,支持随机选择、超时控制及非阻塞操作,建议合理使用以避免协程泄漏和死循环,感兴趣的可以了解一下... 目录一、什么是select基本语法:二、select 使用示例示例1:监听多个通道输入三、select的特性四、使用se

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路