误用gorm引起的一宗血案
现象
某服务A从晚上6点开始,监控一直出现mysql
调用延迟超高,http接口500飙升
原因
经查发现是一条全局update整张表的sql引起的,全局lock表
最小化
使用下面操作进行最小化
建库 create databses test;
建表 CREATE TABLE `Record` ( `id` BIGINT NOT NULL, `count` BIGINT NOT NULL, PRIMARY KEY(`id`) ) ENGINE = InnoDB;
插入一条数据 CREATE TABLE `Record` ( `id` BIGINT NOT NULL, `count` BIGINT NOT NULL, PRIMARY KEY(`id`) ) ENGINE = InnoDB;
代码如下:
package main
import (
"bufio"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"log"
"os"
)
type Record struct {
Id int64 `gorm:"column:id;type:bigint;primary_key",db:"id"`
Count int64 `gorm:"column:count;type:bigint",db:"count"`
}
func (Record) TableName() string {
return "Record"
}
func main() {
var bio *bufio.Reader
var db *gorm.DB
var err error
log.Printf("############# main")
bio = bufio.NewReader(os.Stdin)
bio.ReadString('\n')
// 连接数据库
db, err = gorm.Open("mysql", "root:123456@/test?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic("db link failed")
}
defer db.Close()
log.Printf("db link")
bio = bufio.NewReader(os.Stdin)
bio.ReadString('\n')
// 查找数据
var record Record
queryResult := db.Where("id = ?", 20).Find(&record)
if queryResult.RecordNotFound() {
log.Printf("Not found")
return
}
log.Printf("############ pass NOTFOUND")
bio = bufio.NewReader(os.Stdin)
bio.ReadString('\n')
//if queryResult.Error != nil {
// log.Fatalf("Error %s ", queryResult.Error)
// return
//}
log.Printf("search ok ")
// 更新数据
if err = db.Model(&record).UpdateColumn("count", record.Count+1).Error; err != nil {
panic(err)
}
log.Printf("update ok ")
}
复现步骤,就是
1.运行程序,连接db
2.关闭数据库
3.回车继续程序,程序执行到查询id = 20
,这时候db连接是有错误的,但是找到数据、非RecordNotFound
的错误都是返回true
4.开启数据库
5.回车继续程序,程序执行到更新数据库的数据,传入record
主键id
是一个空,导致会更新全表,并且覆盖所有count = 1
幸好表很大,导致超时,该类操作的数据都被回滚了