关于乐观锁占用mysql连接的疑惑
老师,关于这里业务代码,我贴了我写的demo的核心的代码如下:
大概是这样的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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,都会设置连接池参数的,比如:
1 2 3 4 5 6 7 8 9 10 | 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开发工程师全新版
- 参与学习 508 人
- 解答问题 586 个
风口上的技术,薪资水平遥遥领先,现在学习正值红利期! 未来3-5年,Go语言势必成为企业高性能项目中不可替代的语言 从基础到项目实战再到重构,对转行人员友好,真正从入门到精通!
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧