一 問題描述
Lock wait timeout exceeded; try restarting transaction
二 處理過程
首先假如在生產中遇到這個問題,我們必然是先找到這個循環等待的線程,給他kill了,如下
然后kill掉957和958
三 系統調節
一般mysql的inodb有個默認事物等待時間,超過這個時間他會自動結束且拋出異常,參數為innodb_lock_wait_timeout,默認50s,修改它即可
四 代碼鏈路追蹤
分析出代碼是在同一個表的同一行進行第二次updt操作的時候鎖住了,然后也查閱相關資料,發現有的coder說這種情況會發生鎖死。然后本人做了個測試
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" "time" ) var MysqlDb *sql.DB var MysqlDbErr error // 初始化鏈接 //func InitDb() { func init() { m_user := "wbw" m_pd := "123456" m_host := "127.0.0.1" m_pt := "3306" m_db := "test_local" dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s", m_user, m_pd, m_host, m_pt, m_db, "utf8") // 打開連接失敗 MysqlDb, MysqlDbErr = sql.Open("mysql", dbDSN) //defer MysqlDb.Close(); if MysqlDbErr != nil { panic("數據源配置不正確: " + MysqlDbErr.Error()) } // 最大連接數 MysqlDb.SetMaxOpenConns(100) // 閑置連接數 MysqlDb.SetMaxIdleConns(20) // 最大連接周期 MysqlDb.SetConnMaxLifetime((30)*time.Second) if MysqlDbErr = MysqlDb.Ping(); nil != MysqlDbErr { panic("數據庫鏈接失敗: " + MysqlDbErr.Error()) } } func main(){ //ifupdt,err := UpdtCarrierRemark("asd","hah2") ifupdt,err := UpdtCarrierRemarkTrx("asd","hatt") fmt.Println(ifupdt,err) } func UpdtCarrierRemark(asn_id string,remark string) (bool,error){ _,errs := MysqlDb.Exec("update ls_wms_asn set " + "remark=? where (asn_id=?) ",remark,asn_id) if errs != nil{ fmt.Println(errs) return false,errs } return true,nil } func UpdtCarrierRemarkTrx(asn_id string,remark string) (bool,error){ tx, _ := MysqlDb.Begin() _,errs := tx.Exec("update ls_wms_asn set " + "remark=? where (asn_id=?) ",remark,asn_id) if errs != nil{ fmt.Println(errs) tx.Rollback() return false,errs } _,errs2 := tx.Exec("update ls_wms_asn set " + "remark_ct=201 where (asn_id=?) ",asn_id) if errs2 != nil{ fmt.Println(errs2) tx.Rollback() return false,errs2 } tx.Commit() return true,nil }
做了驗證后發現並沒有發生鎖死的情況,然后猜測可能是並發不夠,所以專門又用ab測試了1s鍾100次的並發,也未發生鎖死。
所以暫時排除此種原因
五 小失誤導致
原來我代碼中用的是MysqlDb.Exec,而非tx.Exec
當我們開啟事務tx, _ := MysqlDb.Begin()后,對db的操作都應該用tx來完成,而非常規的DB單例變量。
雖然原因找到了,是個簡單失誤,但是能夠簡單回顧下事物鎖死的處理過程,也算小有收獲