gpt4 book ai didi

使用相同的 SQL 查询时,Go 包 "database/sql"得到了不同的结果

转载 作者:IT王子 更新时间:2023-10-29 01:44:38 25 4
gpt4 key购买 nike

package main

import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)

func main() {
db, _ := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")

// Just Query
rows, _ := db.Query("SELECT id FROM test_1 WHERE id=123456")
for rows.Next() {
var id interface{}
rows.Scan(&id)
fmt.Println("Query no args =>", id)
}

// Query with args
rows, _ = db.Query("SELECT id FROM test_1 WHERE id=?", 123456)
for rows.Next() {
var id interface{}
rows.Scan(&id)
fmt.Println("Query has args =>", id)
}
}

输出:

$ go run main.go
Query no args => [49 50 51 52 53 54]
Query has args => 123456

问题:

在我看来,"SELECT id FROM test_1 WHERE id=123456""SELECT id FROM test_1 WHERE id=?", 123456 是相同的 SQL 查询。

为什么结果的TYPE不一样?

这是一个错误还是只是不友好的 API 设计?

最佳答案

这与问题 #366 有关。 MySQL 中有两种协议(protocol):

  1. 文本协议(protocol)。当使用文本协议(protocol)时,无论列的类型如何,查询结果都将存储为[]byte。相关源代码可以在方法 textRows.readRow 中找到。进一步的转换将在 rows.Scan 期间完成,它是 database/sql 包的一部分。此处,结果将从 []byte 转换(如果可转换)为传递给 Scan 的参数类型。
  2. 较新的二进制协议(protocol)。使用此协议(protocol)时,查询结果将根据列的类型转换为适当的类型。相关源代码可以在 binaryRows.readRow 找到。

在这道题中,由于Scan参数的类型是interface{},在database/sql端,不会发生转换。当发出不带参数的查询时,驱动程序似乎将使用文本协议(protocol),但当查询有参数时,驱动程序将创建准备语句然后进行通信使用二进制协议(protocol)到服务器。简而言之:

  1. 查询无参数:文本协议(protocol) → 结果为 []byte → 结果扫描到 interface{} → 结果作为 ASCII 码返回123456(即 [49 50 51 52 53 54])。
  2. 使用 args 查询:二进制协议(protocol) → 基于列类型的转换 (int64) → 结果扫描到 interface{} → 结果返回为int64

如果您想获得相同的结果,请使用以下代码进行第一次查询(为清楚起见,省略了错误处理):

//Comment out
//rows, _ := db.Query("SELECT id FROM test_1 WHERE id=123456")

//then replace with
stmt, _ := db.Prepare("SELECT id FROM test_1 WHERE id=123456")
defer stmt.Close()
rows, _ := stmt.Query()

关于使用相同的 SQL 查询时,Go 包 "database/sql"得到了不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45936745/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com