MYSQL乐观锁实现

目录

一、实现方法:

二、伪SQL代码

三、go代码实现:

四、优缺点:


一、实现方法:

        通过对数据表增加一个数字类型的version字段来实现。读取记录时,将version字段一同读出,数据每更新一次,对version字段+1。当更新记录时,检查记录当前version是否与之前读取时的相同,只有相同才给予记录更新操作。

        乐观锁不是数据库自带的,需要自己在代码中实现。乐观锁指更新数据库时,想法很乐观,认为这次操作不会导致冲突。在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新时,再去判断是否有冲突了。整体思想就是CAS思想。

        从字面意思看,用于读多写少的场景。

二、伪SQL代码

SELECT count,version FROM product WHERE id = 10000;
UPDATE product SET count = count -1,version = version+1 WHERE id = 10000 AND version= oldversion;

三、go代码实现:

package main

import (
	"fmt"
	"log"
	"sync"
	"sync/atomic"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
)

type Product struct {
	ID      int `gorm:"primaryKey"`
	Count   int
	Version int
}

var DSN = "root:123@tcp(192.168.4.41:3306)/test?charset=utf8mb4"
var DB *gorm.DB

func init() {
	var err error
	DB, err = gorm.Open(mysql.Open(DSN), &gorm.Config{
		AllowGlobalUpdate: true,
		PrepareStmt:       true,
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
	})
	if err != nil {
		log.Fatalln(err)
	}
	DB.Exec("DROP TABLE IF EXISTS product")
	DB.AutoMigrate(Product{})
	DB.Create(Product{ID: 10000, Count: 10, Version: 0})
}

//减库存
func Decr(id int) bool {
	for {
		var product Product
		DB.Debug().First(&product, id)
		if product.ID == 0 || product.Count <= 0 {
			return false
		}

		rf := DB.Debug().Exec("UPDATE product SET count = count -1,version = version +1 WHERE id = ? AND version = ?", id, product.Version).RowsAffected
		if rf > 0 {
			return true
		}
	}

	return false
}

func main() {
	var count int32
	wg := sync.WaitGroup{}
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			if ret := Decr(10000); ret {
				atomic.AddInt32(&count, 1)
			}
		}()
	}
	wg.Wait()
	fmt.Println("成功更新记录数:", count)
}

运行结果:只能有10个协程更新成功!

数据库库存成功减到零。

四、优缺点:

1.优点:在读操作下,不需要频繁加锁解锁来消耗系统资源,比较轻量

2.缺点:在写操作较多时,很多线程会不断循环来判断锁的状态,这给cpu带来很大的开销。所以乐观锁只适合读多写少的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值