由 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, 滿心激動的查了下去. 直到最終發現問題的時候, 我懵逼了.
之前我哥就和我說, 查問題要從表現去推測. 而這次就是直接奔著底層去了, 結果做了很多無用功.
我回想了一下, 當時正確的檢查步驟應該是:
步驟簡單來說, 就是自上而下, 先從外層找問題, 當發現外層一切正常, 再向里邊找, 就像剝洋蔥一樣, 一層一層, 直到定位到問題所在.
總結
以上是生活随笔為你收集整理的由 go orm 引发的探索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Wordpress不同页面显示不同小工具
- 下一篇: 为什么同大取大同小取小_不锈钢马大型动物