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 关注
- 125 浏览
添加回答
举报