gorm使用事務併發情況下切有最大mysql連線數限制的情況下的BUG,踩坑了

ayanmw發表於2024-03-14

現象

伺服器pprof中的goroutines 很多,無法釋放,肯定是異常.

程式碼


// 收到 請求上個賽季個人秘境賽季排行
func (this *MsgProc) MsgProc_PersonSecretLastRankReq(msg *protoMsg.PersonSecretLastRankReq) {
	global.GetSrvInst().GetThreadGo().Go(func(ctx context.Context) {
		global.GetSrvInst().GetMysqlConn().Transaction(func(tx *gorm.DB) error {
			// 拿到當前資料
			var mynode *protoMsg.PersonSecretRankMD
			global.GetSrvInst().GetMysqlConn().Where("seasonid=? and pid=?", msg.SeasonID, msg.PID).Find(&mynode)
			if mynode == nil || mynode.SeasonID == 0 || mynode.PID == 0 {
				// 空資料
				server.PostPlayerSrv(msg.PID, gcommon.ServerTypeLobby, &protoMsg.PersonSecretLastRankRet{
					LastSeasonID:   msg.SeasonID,
					PID:            msg.PID,
					LastSeasonRank: 0,
				})
				return nil
			}
			server.PostPlayerSrv(msg.PID, gcommon.ServerTypeLobby, &protoMsg.PersonSecretLastRankRet{
				LastSeasonID:      msg.SeasonID,
				PID:               msg.PID,
				LastSeasonRank:    mynode.SeasonRank,
				LastSeasonEndTime: mynode.UpdatedAt.Unix(),
			})
			return nil
		})
	})
}

結論

在gorm的transaction中, Begin會申請一個conn連結, 然後內部如果在獲取新的Mysql Conn的話, 當conn達到maxNum的時候,就會卡住, transaction無法自動釋放conn,進而導致雪崩,其他的程式碼想要呼叫mysql都會出現等待conn的死鎖情況.

所以 在 transaction 的程式碼中, 要用 tx 物件,不要用新的物件.

ps: 這程式碼是同事寫的,但是引以為戒. 順便 get 到gorm事務的踩坑用法,知道為什麼這麼寫更重要.

相關文章