亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

是否可以將 golang db.Query() 輸出轉儲到字符串?

是否可以將 golang db.Query() 輸出轉儲到字符串?

Go
米脂 2022-01-04 20:55:48
我有一個小的 Heroku 應用程序,我在其中打印出查詢執行后每一行的姓名和年齡。我想避免循環行。Next(),Scan().. 只想顯示查詢執行后返回的數據庫可能是一些數據或錯誤。我們可以直接將數據轉儲到字符串中進行打印嗎?rows, err := db.Query("SELECT name FROM users WHERE age = $1", age)if err != nil {    log.Fatal(err)}for rows.Next() {    var name string    if err := rows.Scan(&name); err != nil {        log.Fatal(err)    }    fmt.Printf("%s is %d\n", name, age)}if err := rows.Err(); err != nil {    log.Fatal(err)}
查看完整描述

1 回答

?
天涯盡頭無女友

TA貢獻1831條經驗 獲得超9個贊

差不多:沒有。


Query 方法將返回一個指向 Rows 結構的指針:


func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

如果你打印那個 ( fmt.Printf("%#v\n", rows)) 你會看到這樣的東西:


&sql.Rows{dc:(*sql.driverConn)(0xc8201225a0), releaseConn:(func(error)(0x4802c0), rowsi:(*pq.rows)(0xc820166700), closed:false, lastcols:[]driver.Value(nil), lasterr:error(nil), closeStmt:driver.Stmt(nil)}


...可能不是你想要的。


這些對應于sql 包中的 Rows 結構(您會注意到字段未導出):


type Rows struct {

    dc          *driverConn // owned; must call releaseConn when closed to release

    releaseConn func(error)

    rowsi       driver.Rows


    closed    bool

    lastcols  []driver.Value

    lasterr   error       // non-nil only if closed is true

    closeStmt driver.Stmt // if non-nil, statement to Close on close

    }

你會看到 []driver.Value(來自驅動程序包的一個接口),看起來我們可以期望找到一些有用的,甚至是人類可讀的數據。但是當直接打印時它似乎沒有用,它甚至是空的......所以你必須以某種方式獲取底層信息。sql 包為我們提供了 Next 方法:


Next 準備下一個結果行以使用 Scan 方法讀取。成功時返回 true,如果沒有下一個結果行或在準備它時發生錯誤,則返回 false。應咨詢 Err 以區分這兩種情況。


對 Scan 的每次調用,即使是第一個調用,都必須在調用 Next 之前。


接下來將制作一個 []driver.Value 與我擁有的列數相同的大小,它可以通過 driver.Rows(rowsi 字段)訪問(在 sql 包中),并用查詢中的值填充它。


在調用 rows.Next() 之后,如果你做了同樣的事情,fmt.Printf("%#v\n", rows) 你現在應該看到 []diver.Value 不再是空的,但它仍然不是你可以閱讀的任何東西,更可能是類似的東西:[]diver.Value{[]uint8{0x47, 0x65...


而且由于該字段未導出,您甚至無法嘗試將其轉換為更有意義的內容。但是 sql 包為我們提供了一種對數據進行處理的方法,即 Scan。


Scan 方法非常簡潔,有冗長的注釋,我不會在此處粘貼,但真正重要的一點是它涵蓋了您從 Next 方法和調用獲得的當前行中的列convertAssign(dest[i], sv),您可以在此處看到: https ://golang.org/src/database/sql/convert.go


它很長但實際上相對簡單,它本質上是切換源和目標的類型,并在可能的地方進行轉換,然后從源復制到目標;函數注釋告訴我們:


convertAssign 將 src 中的值復制到 dest,如果可能,將其轉換。如果副本會導致信息丟失,則會返回錯誤。dest 應該是一個指針類型。


所以現在你有了一個方法 (Scan),你可以直接調用它,并返回轉換后的值。您上面的代碼示例很好(除了可能在 Scan 錯誤時調用 Fatal() )。


重要的是要意識到 sql 包必須與特定的驅動程序一起使用,而該驅動程序又是為特定的數據庫軟件實現的,因此在幕后進行了相當多的工作。


我認為如果你想隱藏/概括整個 Query() ---> Next() ---> Scan() 習慣用法,你最好的選擇是將它放到另一個在幕后執行的函數中......寫一個您在其中抽象出更高級別的實現的包,因為 sql 包抽象了一些特定于驅動程序的細節,轉換和復制,填充行等。


查看完整回答
反對 回復 2022-01-04
  • 1 回答
  • 0 關注
  • 239 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號