记录一次可笑的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

  1. 我最开始想使用日志,我的postgre跑在docker上,我google了一下,发现有点复杂,而且要更改设置,很麻烦。

  2. 然后我发现docker logs 可以也可以打印日志,但是发现这是容器的,和数据库没多大关系

  3. 我开始对gorm产生了怀疑,开始翻看文档,但是我确实是按照文档开发的,肯定没问题啊

  4. 我想到,解决问题,最好是尝试描述出来,描述出来就解决一大半了,于是我把问题描述出来给了chatgpt,其实这个时候我还是很困惑,描述不出个大概,也觉得gpt给出的每个问题我都没犯,所以我还叫gpt修改代码,让sql查询详细解释出来

  5. 打印了sql日志,我发现,调用插入特殊支持的语句压根没执行。这时候我开始使用长期依赖的打印大法,确定了一件事,就是特殊支持的插入语句想要执行,但是却没执行

  6. 我终于意识到,这好像是回滚rollback,我赶紧快速写了个打印,发现确实是掉用了回滚,这下就好办了,加入

        debug.PrintStack()
        这是打印为什么回滚的接口
  1. 这个时候就已经差不多明白了,其实只是简单的Create(cardSupportInfo)没有使用指针,而是直接使用的结构体。

经验

其实很多时候对原理的深刻理解很重要,如果能尽早意识到发生了回滚,而不是纠结为什么不return err,很快就解决了。

fmt.println大法其实并不是一点优点都没有,人一生要接触很多语言,无数框架,难道你都能熟悉所有的错误日志打印方法吗?都能一开始就很规范吗。很显然不能。打印能快速定位,多几个打印对程序的执行过程就会有很清晰的概念。

描述问题,很重要,描述的过程中其实是个主动的更深刻的理解自己的代码的过程,你要是理解了发生了什么,总有大佬解决过,你要做的只是告诉google 然后照葫芦画瓢。