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

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

Go SQL查詢不一致

Go SQL查詢不一致

Go
翻過高山走不出你 2023-06-12 09:32:11
我在執行查詢時遇到了一些非常奇怪的不一致,想知道是否有人知道為什么。假設我有一個定義如下的結構:type Result struct {    Afield string      `db:"A"`    Bfield interface{} `db:"B"`    Cfield string      `db:"C"`    Dfield string      `db:"D"`}以及具有以下列的 MySQL 表:A : VARCHAR(50)B : INTC : VARCHAR(50)D : VARCHAR(50)我要執行的查詢:從表中選擇 A、B、C、D WHERE A="a"它可以執行的第一種方式:db.Get(&result, `SELECT A, B, C, D FROM table WHERE A="a"`)第二種執行方式:db.Get(&result, `SELECT A, B, C, D FROM table WHERE A=?`, "a")我遇到的不一致情況如下: 第一種方式執行查詢時,Bfield 的類型是int. 但是,當第二次執行查詢時,它是[]uint8。例如,當 B 為 1 時,就會出現這種結果。為什么 Bfield 的類型會根據查詢的執行方式而有所不同?連接聲明:// Connection is an interface for making queries.type Connection interface {    Exec(query string, args ...interface{}) (sql.Result, error)    Get(dest interface{}, query string, args ...interface{}) error    Select(dest interface{}, query string, args ...interface{}) error}編輯使用 Go 數據庫/sql 包 + 驅動程序也會發生這種情況。下面的查詢分別分配Bfield給[]uint8和int64。db 是 *sql.DB 類型查詢 1:db.QueryRow(SELECT A, B, C, D FROM table WHERE A="a").Scan(&result.Afield, &result.Bfield, &result.Cfield, &result.Dfield)--> 類型Bfield是[]uint8查詢 2:db.QueryRow(SELECT A, B, C, D FROM table WHERE A=?, "a").Scan(&result.Afield, &result.Bfield, &result.Cfield, &result.Dfield)--> 類型Bfield是int64編輯還有一點需要注意,當鏈接多個 WHERE 子句時,只要使用 填充至少?1 個,查詢就會返回int。否則,如果它們都填充在字符串中,它將返回[]uint8
查看完整描述

2 回答

?
慕尼黑8549860

TA貢獻1818條經驗 獲得超11個贊

簡短回答:因為 MySQL 驅動程序對帶參數和不帶參數的查詢使用不同的協議。使用準備好的語句來獲得一致的結果。

以下解釋參考標準MySQL驅動

在第一種情況下,驅動程序直接將查詢發送到 MySQL,并將結果解釋為結構*textRows。這個結構(幾乎)總是將結果解碼為一個字節 slice,并將轉換為更好的類型留給 Gosql包。如果目標是int,等,這可以string正常工作sql.Scanner,但不適用于interface{}.

在第二種情況下,驅動程序檢測到有參數并返回driver.ErrSkip。這會導致 Go SQL 包使用 PreparedStatement。在這種情況下,MySQL 驅動程序使用一個*binaryRows結構來解釋結果。此結構使用聲明的列類型(INT在本例中)解碼值,在本例中將值解碼為int64.

有趣的事實:如果您將interpolateParams=true參數提供給數據庫 DSN(例如"root:testing@/mysql?interpolateParams=true"),MySQL 驅動程序將在客戶端準備查詢,而不是使用 PreparedStatement。此時,兩種類型的查詢行為相同。

一個小的概念證明:

package main


import (

? ? "database/sql"

? ? "log"


? ? _ "github.com/go-sql-driver/mysql"

)


type Result struct {

? ? Afield string

? ? Bfield interface{}

}


func main() {

? ? db, err := sql.Open("mysql", "root:testing@/mysql")

? ? if err != nil {

? ? ? ? log.Fatal(err)

? ? }

? ? defer db.Close()


? ? if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS mytable(A VARCHAR(50), B INT);`); err != nil {

? ? ? ? log.Fatal(err)

? ? }

? ? if _, err = db.Exec(`DELETE FROM mytable`); err != nil {

? ? ? ? log.Fatal(err)

? ? }

? ? if _, err = db.Exec(`INSERT INTO mytable(A, B) VALUES ('a', 3)`); err != nil {

? ? ? ? log.Fatal(err)

? ? }


? ? var (

? ? ? ? usingLiteral? ? ? ? ?Result

? ? ? ? usingParam? ? ? ? ? ?Result

? ? ? ? usingLiteralPrepared Result

? ? )

? ? row := db.QueryRow(`SELECT B FROM mytable WHERE A='a'`)

? ? if err := row.Scan(&usingLiteral.Bfield); err != nil {

? ? ? ? log.Fatal(err)

? ? }

? ? row = db.QueryRow(`SELECT B FROM mytable WHERE A=?`, "a")

? ? if err := row.Scan(&usingParam.Bfield); err != nil {

? ? ? ? log.Fatal(err)

? ? }

? ? stmt, err := db.Prepare(`SELECT B FROM mytable WHERE A='a'`)

? ? if err != nil {

? ? ? ? log.Fatal(err)

? ? }

? ? defer stmt.Close()

? ? row = stmt.QueryRow()

? ? if err := row.Scan(&usingLiteralPrepared.Bfield); err != nil {

? ? ? ? log.Fatal(err)

? ? }


? ? log.Printf("Type when using literal:? %T", usingLiteral.Bfield)? ? ? ? ?// []uint8

? ? log.Printf("Type when using param:? ? %T", usingParam.Bfield)? ? ? ? ? ?// int64

? ? log.Printf("Type when using prepared: %T", usingLiteralPrepared.Bfield) // int64

}


查看完整回答
反對 回復 2023-06-12
?
浮云間

TA貢獻1829條經驗 獲得超4個贊

您在 MySql 中的第一個 SQL 字符串是不明確的,

根據 SQL-MODE,您的 SQL 命令可以解釋為

SELECT?A,?B,?C,?D?FROM?table?WHERE?A='a'

這就是我認為你所期待的。

或者作為

SELECT?A,?B,?C,?D?FROM?table?WHERE?A=`a`

為了避免這種歧義,你能做一個新的 FIRST 測試來用單引號替換雙引號嗎?

如果相同的行為繼續存在,我的回答不是一個好的回應。

如果 BOTH SQL select 返回相同的值,你的問題就解決了。

使用 ` 字符,您傳遞的是變量名而不是字符串值!


查看完整回答
反對 回復 2023-06-12
  • 2 回答
  • 0 關注
  • 182 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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