zoukankan      html  css  js  c++  java
  • 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单例变量。

      虽然原因找到了,是个简单失误,但是能够简单回顾下事物锁死的处理过程,也算小有收获

  • 相关阅读:
    机器语言 汇编语言 C C++ Java C# javaScript Go 编译型语言 解释型语言
    计算机历史(二战前)
    可维护性组件的编写原则
    the lasted discuss about h5 optimize
    The last discussion about the inherit
    The last discussion about the prototype
    font-size line-height vertual-align的复杂关系
    vertical-align
    retina屏 适配问题
    XMLHttpRequest2.0的进步之处
  • 原文地址:https://www.cnblogs.com/bushuwei/p/15740824.html
Copyright © 2011-2022 走看看