栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

去SQL查询不一致

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

去SQL查询不一致

简短的答案:因为MySQL驱动程序对带有参数和不带有参数的查询使用不同的协议。使用准备好的语句以获得一致的结果。

以下说明引用了标准MySQL驱动程序github.com/go-sql-driver/mysql 1.4版

在第一种情况下,驱动程序将查询直接发送到MySQL,并将结果解释为

*textRows
结构。这个结构(几乎)总是将结果解码为字节片,并将转换结果转换为更好的类型给Go
sql
包。这工作正常,如果目标是
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 mainimport (    "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        usingParamResult        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}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/484338.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号