golangmysql⾼并发_golang⾼并发数据库库存同步处理⽅法⼀(对数据库的读写操作加锁)
⼀(DAO层加⾏锁:读写锁)
package main
import (
"sync"
)
//1、多个读之间不存在互斥关系
//2、写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的
type idMutex map[string] *sync.RWMutex
var myIdMutex idMutex
func init() {
myIdMutex=make(map[string] *sync.RWMutex)
}
//读锁定
func (this *idMutex)RLock(id string){
m,ok:=(*this)[id]
if !ok {
m=new(sync.RWMutex)
(*this)[id]=m
}
m.RLock()
}
/
/读解锁
func (this *idMutex)RUnlock(id string){
m,ok:=(*this)[id]
if !ok {
四个字的成语return
}
m.RUnlock()
}
//写操作锁定
func (this *idMutex)Lock(id string){
m,ok:=(*this)[id]
if !ok {
m=new(sync.RWMutex)
(*this)[id]=m
}
m.Lock() //写操作锁定
}
//写操作解锁
func (this *idMutex)Unlock(id string) {
m,ok:=(*this)[id]
if !ok {
return
}
m.Unlock()//写操作解锁
}
type Accout struct {
Id string
}
//进⾏读的操作
func (this *Accout) Reed() {
myIdMutex.RLock(this.Id)
defer myIdMutex.RUnlock(this.Id)
}
/
/进⾏写的操作
func (this *Accout) Write() {
myIdMutex.Lock(this.Id) //写操作锁定
defer myIdMutex.Unlock(this.Id) //写操作解锁}
社保卡怎么激活func main() {
acout:=Accout{Id:"798456"}
acout.Reed()
acout.Write()
}
国庆节的意义简短⼀(对象加锁) 将读写的⽅法封装,并且添加锁type Accout struct {
flag sync.Mutex //sync.Mutex类型
}
freebuds pro//进⾏读的操作
func (a *Accout) Reed(n int) { //读
a.flag.Lock() //锁上
defer a.flag.Unlock() //在⽅法运⾏完之后解开
}
//进⾏写的操作
func (a *Accout) Write(n int) { //读
a.flag.Lock() //锁上
defer a.flag.Unlock() //在⽅法运⾏完之后解开
}
⽅法⼆(直接对数据库进⾏操作)
原理
数据库使⽤InnoDB
InnoDB与MyISAM的最⼤不同有两点:⼀是⽀持事务(TRANSACTION);⼆是采⽤了⾏级锁。
InnoDB实现了以下两种类型的⾏锁。
共享锁(s):允许⼀个事务去读⼀⾏,阻⽌其他事务获得相同数据集的排他锁。
排他锁(X):允许获取排他锁的事务更新数据,阻⽌其他事务取得相同的数据集共享读锁和排他写锁。
另外,为了允许⾏锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使⽤的意向锁(Intention Locks),这两种意向锁都是表锁。
意向共享锁(IS):事务打算给数据⾏共享锁,事务在给⼀个数据⾏加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据⾏加排他锁,事务在给⼀个数据⾏加排他锁前必须先取得该表的IX锁。
如果⼀个事务请求的锁模式与当前的锁兼容,InnoDB就请求的锁授予该事务;反之,如果两者两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB⾃动加的,不需⽤户⼲预。对于UPDATE、DELETE和INSERT语句,InnoDB会⾃动给涉及及数据集加排他锁(X)(允许获取排它锁的事物进⾏操作,其他事物处于阻塞状态);对于普通SELECT语句,InnoDB不会任何锁;事务可以通过以下语句显⽰给记录集加共享锁或排锁。
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
代码
package main
import(
"database/sql"
_"github/go-sql-driver/mysql"
"log"
"time"
"math/rand"
)
// 连接池⼤⼩
var MAX_POOL_SIZE = 20
var dbPoll chan *sql.DB
const (
user="root"
pass="root"
db="school"
)
func putDB(db *sql.DB) {
// 基于函数和接⼝间互不信任原则,这⾥再判断⼀次,养成这个好习惯哦
if dbPoll == nil {
dbPoll = make(chan *sql.DB, MAX_POOL_SIZE)
}
if len(dbPoll) >= MAX_POOL_SIZE {
db.Close()
return
}
dbPoll
}
func initDB() {
// 缓冲机制,相当于消息队列
if len(dbPoll) == 0 {
// 如果长度为0,就定义⼀个redis.Conn类型长度为MAX_POOL_SIZE的channel
dbPoll = make(chan *sql.DB, MAX_POOL_SIZE)
go func() {
英语四级多少分能过for i := 0; i < MAX_POOL_SIZE/2; i++ {
db,err:=sql.Open("mysql",user+":"+pass+"@tcp(localhost:3306)/"+db+"?charset=utf8") if err!=nil {
log.Println(err)
}
putDB(db)
}
} ()
}
}
func GetDB() *sql.DB {
//如果为空就初始化或者长度为零
if dbPoll == nil||len(dbPoll) == 0{
initDB()
}
return
}
func main(){
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i:=0;i<10 ;i++ {
邱心志个人资料go changeCount(r.Intn(50))
go changeCount(r.Intn(50))
go changeCount(r.Intn(50))
go changeCount(r.Intn(50))
}
time.Sleep(3*time.Second)
}
func changeCount(num int ) {
db:=GetDB()
tx, err := db.Begin()//打开事物
defer tx.Commit()//事物提交
//意向共享锁(IS):事务打算给数据⾏共享锁,事务在给⼀个数据⾏加共享锁前必须先取得该表的IS锁。//意向排他锁(IX):事务打算给数据⾏加排他锁,事务在给⼀个数据⾏加排他锁前必须先取得该表的IX锁。//意向锁是InnoDB⾃动加的,不需⽤户⼲预。
res,_ := tx.Exec("UPDATE product set count=count-? WHERE Id=1 AND count>=? ",num,num) RowsAffected, err := res.RowsAffected()
if err != nil {
log.Println("res.RowsAffected==================Err")
}
if RowsAffected>0 {
addToOrder()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论