关于乐观锁占用mysql连接的疑惑
老师,关于这里业务代码,我贴了我写的demo的核心的代码如下:
大概是这样的逻辑
tx := db.DB.Begin() for _, goodsInfo := range req.GoodsInfo { for { inv := db.Inventory{} // 这里实现乐观锁的时候,查询数据,一定不要用事务!不然拿不到最新的数据! result := db.DB.Where(map[string]interface{}{"goods": 1}).Limit(1).Find(&inv) //省略一些错误判断 // 扣减库存 inv.Stocks -= goodInfo.Num // 指定更新version=查询到的version值。并且此操作也要对version进行+1 res := tx.Model(&db.Inventory{}).Select("stocks", "version"). Where("goods = ? AND version = ?", inv.Goods, inv.Version). Updates(db.Inventory{ Stocks: inv.Stocks, Version: inv.Version + 1, }) if res.Error != nil { tx.Rollback() fmt.Printf("商品库存更新失败: %+v", result.Error) return } if res.RowsAffected == 1 { break } } } tx.Commit()
这里在for循环最外面开启了事务,然后里面每个商品都死循环去扣减库存,是不是意味着,在循环等待的时候占用了mysql的一个连接?
因为一般情况我们在项目里使用gorm,都会设置连接池参数的,比如:
DB, err = gorm.Open(mysql.Open(dsn)) sqlDB, err := DB.DB() // SetMaxIdleConns 设置空闲连接池中连接的最大数量 sqlDB.SetMaxIdleConns(10) // SetMaxOpenConns 设置打开数据库连接的最大数量。 sqlDB.SetMaxOpenConns(100) // SetConnMaxLifetime 设置了连接可复用的最大时间。 sqlDB.SetConnMaxLifetime(time.Hour)
那么我的问题是:
1.并发超过100个扣库存,是不是就把连接给全部占满了?服务就挂了? 我实测并发高一点就卡住了,如果不加连接池设置,那么比如并发500,就会有一段时间,500个开启事务的连接保持着,甚至并发更高,mysql就会报错max_connection了,怎么解决这种问题呢?或者说我这里实现方式有问题吗?
2. 如果我把事务放在for死循环里面,就是每次去update的时候再开启事务,关闭事务,确实连接不会占用了,但是for循环就会不断给mysql发送事务,这样每个update都超级慢。应该是不能这样使用的。
我写乐观锁的demo,就发现,它不如悲观锁性能好,悲观锁简单并发5000个都能很轻松跑完demo。
实际真正开发项目,写代码应该是不能这样写的吧?
请老师指教~
23
收起
正在回答 回答被采纳积分+1
1回答
Go开发工程师全新版
- 参与学习 493 人
- 解答问题 572 个
风口上的技术,薪资水平遥遥领先,现在学习正值红利期! 未来3-5年,Go语言势必成为企业高性能项目中不可替代的语言 从基础到项目实战再到重构,对转行人员友好,真正从入门到精通!
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星