日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

由 go orm 引发的探索

發布時間:2024/8/23 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 由 go orm 引发的探索 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

今天遇到了一個 bug, 是 golang 的orm導致的. 使用了gorm框架. 通過實現Scan與Value可以將數據庫中的 json 內容解析出來, 免除了 字符串再解碼的步驟. 當時報錯的代碼大概是這樣的:

type TestContent struct {Id intContent Content // 數據庫中的 json 結構 }type Content struct {Name stringAge int }func (c *Content) Scan(value interface{}) error {return json.Unmarshal(value.([]byte), c) }func (c *Content) Value() (driver.Value, error) {return json.Marshal(c) }

向數據庫插入數據, 調用Create方法時報錯了:

[2020-08-28 23:18:25] sql: converting argument $1 type: unsupported type main.Content, a struct

這這這, 什么鬼? 當時我百思不得其所. 經過多次嘗試, 我發現將Value方法的從屬從指針類型改為值類型就可以解決這個問題.

此時我恍然大悟, 想起了之前的方法集的概念.

  • 指針類型擁有 值/指針 的方法
  • 值類型只擁有值類型的方法
  • 也就是說, go 在底層是使用值類型來調用的, 所以拿不到指針方法, 故而報錯.

    看到這里, 如果你也遇到同樣的問題, 將Value方法從屬改為值類型就可以解決了. 以下內容是我手賤之后的另一個愚蠢記錄, 可跳過.

    另一個問題

    此時我以為我已經深得精髓, 解決方法很簡單, 將兩個方法的從屬都改為值類型就好了嘛. 修改后, 插入數據果然沒有問題了, 但是當我查詢的時候, 發現了另一個問題,?Content對象沒有賦值, 是空的.

    當時我一臉懵逼, 沒有找到問題所在, 我做了什么? 于是, 我就開始了打斷點之路:

    我發現它走到這里, 調用了Scan方法, 那么, dest 又是個什么對象呢?

    于是, 我又找到了這個賦值的地方, 將類型打印出來后, 是:

    **main.Content

    是一個二級指針, 這時, 我以為是因為二級指針的問題. 于是我動手寫了一段代碼來模擬這段操作:

    func main(){// 這里模擬了當時設置的代碼內容typeOf := reflect.TypeOf(Content{})reflectValue := reflect.New(reflect.PtrTo(typeOf))reflectValue.Elem().Set(reflect.ValueOf(&Content{}))r := reflectValue.Interface()if c, ok := r.(**Content); ok {(**c).SetName("1111")fmt.Println(fmt.Sprintf("%+v", **c))} }// 這里, 為了方便測試, 添加了 SetName 方法, 與 Scan 相同 func (nt Content) SetName(name string) {nt.Name = name }

    當我看到結果的時候, 發現name依舊沒有設置進去. 我了個喵, 什么情況?

    然后我開始了瘋狂檢查的過程, 直到我寫下了這段代碼之后, 我陷入了沉思:

    content := Content{}content.SetName("hh")fmt.Println(fmt.Sprintf("%+v", content))

    當我發現直接設置都沒用的時候, 我知道, 一定是我哪個最簡單的地方出錯了. 我默默的點起一支煙, 望著眼前的代碼發起了呆.

    我經過與之前改動的對比, 知道問題一定是出在指針與值類型的轉換上.

    我我我我的天, 最終我發現我犯了一個多么愚蠢的錯誤. 使用值類型是無法對其字段進行修改的, 其修改通通是通過值復制進行, 并不會影響原始對象. 而且我右打了斷點發現, 方法并不是沒有調, 確實是調用了, 只不過因為從屬與值而沒有對原始對象造成影響.

    總結

    就在我剛開始查這個問題的時候, 我自認為找到了什么不得了的 bug, 滿心激動的查了下去. 直到最終發現問題的時候, 我懵逼了.

    之前我哥就和我說, 查問題要從表現去推測. 而這次就是直接奔著底層去了, 結果做了很多無用功.

    我回想了一下, 當時正確的檢查步驟應該是:

  • 在Scan方法內打斷點, 查看是否調用了方法以及兩次調用傳的參數是否一致
  • 當發現調用方法且參數一致時, 就直接到了最后一步并最終找到指針的問題
  • 若沒有調用方法或參數不一致時, 再往調用的地方去找
  • 步驟簡單來說, 就是自上而下, 先從外層找問題, 當發現外層一切正常, 再向里邊找, 就像剝洋蔥一樣, 一層一層, 直到定位到問題所在.

    總結

    以上是生活随笔為你收集整理的由 go orm 引发的探索的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。