Mysql 事務鎖等待時間超時


一 問題描述

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單例變量。

  雖然原因找到了,是個簡單失誤,但是能夠簡單回顧下事物鎖死的處理過程,也算小有收獲

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM