2 回答

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
}

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 返回相同的值,你的問題就解決了。
使用 ` 字符,您傳遞的是變量名而不是字符串值!
- 2 回答
- 0 關注
- 182 瀏覽
添加回答
舉報