记录一次可笑的debug
-
我遇到了一个有意思的orm框架问题,大概的流程是,将数据先插入cardlist表中,然后如果这个card有特殊支持,则在一个support表中新增内容,我使用的是gorm,然后开启了事务
-
我发现插入的案例有些成功有些失败,很快总结出规律,如果有特殊支持的就插入失败,也没有报错,啥也没有,就是莫名其妙的失败了。数据库和日志中什么都没有。
func InsertNewCard(input InputCardInfo) (err error) {
tx := postdb.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if tx.Error != nil {
return errors.New("tx.begin failed" + tx.Error.Error())
}
cardInfo := CardList{
CardName: input.CardName,
CardIntroduction: input.CardIntroduction,
IsSupportGroup: input.IsSupportGroup,
IsSupportTeam: input.IsSupportTeam,
IsSupportVIP: input.IsSupportVIP,
IsLimitDays: input.IsLimitDays,
IsLimitTimes: input.IsLimitTimes,
IsForbidSpecial: input.IsForbidSpecial,
IsSupportSpecial: input.IsSupportSpecial,
AdminAccount: input.AdminAccount,
Price: input.Price,
}
if err := tx.Error; err != nil {
return err
}
err = tx.Debug().Model(&CardList{}).Create(&cardInfo).Error
if err != nil {
tx.Rollback()
return err
}
loger.Loger.Println("新插入了一个", cardInfo.CardName, cardInfo.CardId, cardInfo.IsForbidSpecial)
if cardInfo.IsForbidSpecial {
for _, forbidInfo := range input.ForbidCourseId {
cardForbidInfo := CardForbidList{
CourseId: forbidInfo,
CardId: cardInfo.CardId,
}
err = tx.Debug().Model(&CardForbidList{}).Create(&cardForbidInfo).Error // 使用 Debug 打印插入操作
if err != nil {
tx.Rollback()
return err
}
}
}
if cardInfo.IsSupportSpecial {
for _, supportInfo := range input.SupportCourseId {
cardSupportInfo := CardSupportList{
CourseId: supportInfo,
CardId: cardInfo.CardId,
}
err = tx.Debug().Model(&CardSupportList{}).Create(cardSupportInfo).Error // 使用 Debug 打印插入操作
if err != nil {
tx.Rollback()
return err
}
}
}
if tx.Error != nil {
loger.Loger.Println("error:", tx.Error.Error())
return tx.Error
}
err = tx.Commit().Error
if err != nil {
loger.Loger.Println(err.Error())
}
return err
}
开始debug
-
我最开始想使用日志,我的postgre跑在docker上,我google了一下,发现有点复杂,而且要更改设置,很麻烦。
-
然后我发现docker logs 可以也可以打印日志,但是发现这是容器的,和数据库没多大关系
-
我开始对gorm产生了怀疑,开始翻看文档,但是我确实是按照文档开发的,肯定没问题啊
-
我想到,解决问题,最好是尝试描述出来,描述出来就解决一大半了,于是我把问题描述出来给了chatgpt,其实这个时候我还是很困惑,描述不出个大概,也觉得gpt给出的每个问题我都没犯,所以我还叫gpt修改代码,让sql查询详细解释出来
-
打印了sql日志,我发现,调用插入特殊支持的语句压根没执行。这时候我开始使用长期依赖的打印大法,确定了一件事,就是特殊支持的插入语句想要执行,但是却没执行
-
我终于意识到,这好像是回滚rollback,我赶紧快速写了个打印,发现确实是掉用了回滚,这下就好办了,加入
debug.PrintStack()
这是打印为什么回滚的接口
- 这个时候就已经差不多明白了,其实只是简单的Create(cardSupportInfo)没有使用指针,而是直接使用的结构体。
经验
其实很多时候对原理的深刻理解很重要,如果能尽早意识到发生了回滚,而不是纠结为什么不return err,很快就解决了。
fmt.println大法其实并不是一点优点都没有,人一生要接触很多语言,无数框架,难道你都能熟悉所有的错误日志打印方法吗?都能一开始就很规范吗。很显然不能。打印能快速定位,多几个打印对程序的执行过程就会有很清晰的概念。
描述问题,很重要,描述的过程中其实是个主动的更深刻的理解自己的代码的过程,你要是理解了发生了什么,总有大佬解决过,你要做的只是告诉google 然后照葫芦画瓢。