記錄一次可笑的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 然后照葫蘆畫瓢。