golang mysql加锁_使用golang实现类InnoDB数据行锁效果
在关系型数据库领域,为人津津乐道的一个特性,便是数据库的锁设计及事务隔离级别。
本文通过golang系统库sync,来实现简单的数据库数据读写操作。
场景说明
小明经营一家水果店,创业初始资金为100000元,所有的收入以及支出通过2个银行账户进行往来。
因交易频繁,可能存在并发更新账户数据及查账的需求,需要保障账户数据针对所有操作的一致性。
此处需要引入读写锁,保障读写的安全性及高效性。
需求分析
在MySQL中,使用InnoDB存储引擎,配合合适的事务隔离级别,可以做到数据行级锁定,也就是:
操作类型
查账户A
查账户B
写账户A
写账户B
查账户A
可并发
可并发
互斥
可并发
查账户B
可并发
可并发
可并发
互斥
写账户A
互斥
可并发
互斥
可并发
写账户B
可并发
互斥
可并发
互斥
账户A和账户B的读写操作相互独立,最大化账户的并发操作。
那么,如何使用golang实现简单表格中的场景呢?另外, 是否可以设置读写的优先级呢?
我们下面先来介绍下golang的两个类:
sync.RWMutex
读写锁,支持单写多读特性。区别于sync.Mutex的全局互斥锁特性(不支持同时读)
sync.WaitGroup
可通过Add方法,将请求分组,同一组的gorountine可通过Wait方法,控制组内所有gorountine全部结束,才能继续主线程,否则一直阻塞主线程。
如下代码为实现样例,假设当前有如下数量请求并发:
5个A账户读,B账号读,3个A账号写,B账户写
其中A账户设置了低优先级读。
功能实现
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
// 账户的初始数据
var accountTypeMap = map[string]int{
"A": 50000,
"B": 50000,
}
// init方法,设置seed,用于控制随机数生成的初始值,确保其随机性
func init() {
rand.Seed(time.Now().Unix())
}
func sleep() {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
}
// 读取账号余额,低优先级的读,采取随机sleep的方式,等待请求
func readAccount(accountType string, m *sync.RWMutex, wg *sync.WaitGroup, lowPriority ...string) {
if (len(lowPriority)) > 0 {
sleep()
}
// 使用读锁
m.RLock()
fmt.Println("time:", time.Now().UnixNano()/1e6, " read account ", accountType, " left money:", accountTypeMap[accountType])
// sleep 10毫秒,方便确认并发是否生效
time.Sleep(time.Duration(10) * time.Millisecond)
// 释放读锁
m.RUnlock()
wg.Done()
}
// 写入账号,低优先级的写,采取随机sleep的方式,等待请求
func writeAccount(accountType string, addMoney int, m *sync.RWMutex, wg *sync.WaitGroup, lowPriority ...string) {
if (len(lowPriority)) > 0 {
sleep()
}
// 使用写锁(排他锁)
m.Lock()
accountTypeMap[accountType] = accountTypeMap[accountType] + addMoney
fmt.Println("time:", time.Now().UnixNano()/1e6, "modify account ", accountType, " add money:", addMoney)
// sleep 10毫秒,方便确认并发是否生效
time.Sleep(time.Duration(10) * time.Millisecond)
m.Unlock()
wg.Done()
}
func main() {
var mutexA sync.RWMutex
var mutexB sync.RWMutex
wg := sync.WaitGroup{}
// 设置5个A账户读,B账号读,3个A账号写,B账户写
for i := 0; i < 5; i++ {
wg.Add(1)
go readAccount("A", &mutexA, &wg, "lowpriority")
}
for i := 0; i < 5; i++ {
wg.Add(1)
go readAccount("B", &mutexB, &wg)
}
for i := 0; i < 3; i++ {
wg.Add(1)
go writeAccount("A", 1000, &mutexA, &wg)
}
for i := 0; i < 3; i++ {
wg.Add(1)
go writeAccount("B", 3000, &mutexB, &wg)
}
wg.Wait()
fmt.Println("account A left: ", accountTypeMap["A"])
fmt.Println("account B left: ", accountTypeMap["B"])
}
结果分析
返回的结果具体随机性,其中A读具有低优先级,返回在最后。以下为一种结果:
time: 1565345040128 modify account B add money: 3000
time: 1565345040128 modify account A add money: 1000
time: 1565345040139 read account B left money: 53000
time: 1565345040139 read account B left money: 53000
time: 1565345040139 modify account A add money: 1000
time: 1565345040139 read account B left money: 53000
time: 1565345040139 read account B left money: 53000
time: 1565345040139 read account B left money: 53000
time: 1565345040149 modify account A add money: 1000
time: 1565345040149 modify account B add money: 3000
time: 1565345040160 modify account B add money: 3000
time: 1565345040493 read account A left money: 53000
time: 1565345040693 read account A left money: 53000
time: 1565345040693 read account A left money: 53000
time: 1565345040828 read account A left money: 53000
time: 1565345041091 read account A left money: 53000
account A left: 53000
account B left: 59000
从前面2行的返回结果看,写账户A和写账户B 可并发操作,
从第3,4,5 行看,读账户B和写账户可并发操作,满足前面表格的场景。
golang mysql加锁_使用golang实现类InnoDB数据行锁效果相关推荐
- golang mysql 崩溃_使用GoLang与mysql连接失败
我试图使用Go语言连接MySql数据库并给我以下错误. sql: unknown driver "mysql" (forgotten import?) 我的守则 package m ...
- golang mysql封装_使用Golang 封装一个Api 框架 ----- 数据库操作篇(gorm引入)
在models/baseModel 定义了 一个BaseModel对象,在这个对象上定义了 获取数据库连接和 释放数据库连接的方法 type BaseModel struct { dbConnect ...
- 【Java面试题】6年开发去A里面试P6竟被Mysql难住了,说一下你对行锁、临键锁、间隙锁的理解
一个工作了6年的程序员,最近去阿里面试p6这个岗位. 面试之前信心满满的和我说,这次一定要拿下 35k月薪的offer. 然后,在第一面的时候,被Mysql里面的一个问题难住了. 大家好,我是Mic, ...
- Mysql INNODB引擎行锁的3种算法 Record Lock Next-Key Lock Grap Lock
Mysql INNODB引擎行锁的3种算法 InnoDB存储引擎有3种行锁的算法,其分别是: □ Record Lock:单个行记录上的锁 Record Lock总是会去锁住索引记录,如果InnoDB ...
- mysql 开启引擎命令_MySql中启用InnoDB数据引擎的方法
1.存储引擎是什么? Mysql中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术, ...
- mysql事务基础+基于innodb的行锁+间隙锁+如何锁定行
[0]README outlines are as follows : 行锁: 事务: 隔离级别: 行锁变表锁: 间隙锁: 如何锁定一行: 行锁总结: [1]行锁+事务+存储引擎基础 1.行锁: 偏向 ...
- golang mysql封装_自己封装的golang 操作数据库方法
这个是我用Go写的第一个东东,可能还存在些BUG没有测试到.这里主要是提供一个参考.各位可以改写成自己的风格. 在命令行下输入如下两条命令,进行安装 go get github.com/male110 ...
- golang 读一行_与golang合作的第一步
golang 读一行 If you like to understand know why we choose golang in the first as an alternative to pyt ...
- golang反编译_【Golang】脱胎换骨的defer(一)
Go语言的defer是一个很方便的机制,能够把某些函数调用推迟到当前函数返回前才实际执行.我们可以很方便的用defer关闭一个打开的文件.释放一个Redis连接,或者解锁一个Mutex.而且Go语言在 ...
最新文章
- 一个例子看懂kotlin的集合和序列
- Python学习基础必备知识点:字典dict详解
- 数据结构与算法 | 二叉树四种的遍历方法(递归与非递归)
- Postgres客户端编码问题
- 【英语学习】【Level 07】U01 Making friends L2 A new friend from the past
- java正则表达式tab_Linux下如何使用grep命令查找带有tab(退格)的字符
- iOS内存分配五大区:
- 庆贺:在国产平台上成功运行gluegen/jogl 2.3.2
- 地图转换|用arcgis 将cad转kmz
- python tokenize_python – 滥用nltk的word_tokenize(已发送)的后果
- 洛谷P1510-精卫填海(01背包)
- Maven中Scop为test时Eclispe中需要注意的地方
- UG/NX二次开发 判断圆柱面是不是孔的方法
- Java“菜单“树递归-合并子树
- 解决xp共享的批处理文件
- ubuntu:下载ubuntu内核
- 安装docker 配置 oracle11g
- 使用Python PySNMP模块获取设备指标
- logAB = logA + logB; A,B0
- python爬网络图片脚步_小白福利!跟着我的脚步!老司机带你爬取整站妹子图!反爬不存在-站长资讯中心...
热门文章
- 利用pandas,matplotlib画饼图
- 匿名内部类 可以访问外部类_Java——内部类详解
- Java方法02 递归
- python控制结构实验结果分析_实验1_Python语法及控制结构
- HTML搜索框中加入提示文字,HTML 5 input placeholder 属性 实现搜索框提示文字点击输入后消失 - 尚码园...
- YApi--使用YApi的目的
- python 时间序列异常值_python中缺少时间序列值
- c++ array容器 传参_C++ 顺序容器基础知识总结
- c++怎么做app_怎么做一款app
- HTML渐变背景不重复,如何停止重复自身的背景颜色渐变? (css)