go语言的gorm事务中使用redsync锁锁不住
在gorm的事务中我开启了20个协程模仿用户删除 但是redsync.Lock()的互斥性消失了 导致都获取了锁
如果我把事务关闭 互斥性就恢复正常了
package main
import (
"fmt"
goredislib "github.com/go-redis/redis/v8"
"github.com/go-redsync/redsync/v4"
"github.com/go-redsync/redsync/v4/redis/goredis/v8"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"log"
"os"
"sync"
"time"
)
var DB *gorm.DB
type BaseModel struct {
ID int32 `gorm:"primary_key;comment:ID" json:"id"`
CreatedAt time.Time `gorm:"column:add_time;comment:创建时间" json:"-"`
UpdatedAt time.Time `gorm:"column:update_time;comment:更新时间" json:"-"`
DeletedAt gorm.DeletedAt `gorm:"comment:删除时间" json:"-"`
IsDeleted bool `gorm:"comment:是否删除" json:"-"`
}
type Inventory struct {
BaseModel
Goods int32 `gorm:"type:int;index;comment:商品id"`
Stocks int32 `gorm:"type:int;comment:仓库"`
Version int32 `gorm:"type:int;comment:分布式锁-乐观锁"`
}
func InitDB() {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "123456", "localhost", 3306, "mxshop_inventory_srv2")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别
//LogLevel: logger.Silent, // 日志级别
//IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 禁用彩色打印
},
)
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
Logger: newLogger,
})
if err != nil {
panic(err)
}
}
func main() {
InitDB()
client := goredislib.NewClient(&goredislib.Options{
Addr: "1.1.1.1:6301",
})
pool := goredis.NewPool(client)
rs := redsync.New(pool)
gNum := 20
var wg sync.WaitGroup
wg.Add(gNum)
DB.Transaction(func(tx *gorm.DB) error {
for i := 0; i < gNum; i++ {
go func() {
defer wg.Done()
var inv Inventory
mutex := rs.NewMutex(fmt.Sprintf("goodsss_%d", 421))
if err := mutex.Lock(); err != nil {
fmt.Println("获取redis分布式锁异常-1")
}
if result := DB.Where(&Inventory{Goods: int32(421)}).First(&inv); result.RowsAffected == 0 {
panic("库存信息不存在")
}
fmt.Println(inv.Stocks)
if err := tx.Model(&Inventory{}).Select("Stocks").Where("goods = ?", int32(421)).Update("stocks", inv.Stocks-1); err.RowsAffected == 0 {
fmt.Println("更新失败:", err.Error.Error())
fmt.Println(inv.Stocks)
}
if ok, err := mutex.Unlock(); !ok || err != nil {
fmt.Println("释放redis分布式锁异常-4")
}
}()
}
return nil
})
wg.Wait()
}