当使用相同的SQL查询时,go包“database / sql”得到了diff-result

时间:2017-08-29 10:28:13

标签: go

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设计?

1 个答案:

答案 0 :(得分:1)

这与问题http://site有关。 MySQL中有两种协议:

  1. 文字协议。使用文本协议时,无论列的类型如何,查询结果都将存储为[]byte。可以在方法#366中找到相关的源代码。进一步转换将在textRows.readRow期间进行,rows.Scandatabase/sql包的一部分。这里,结果将从[]byte转换(如果可转换)到传递给Scan的参数类型。
  2. 较新的二进制协议。使用此协议时,查询结果将根据列的类型转换为适当的类型。相关的源代码可以在binaryRows.readRow找到。
  3. 在这个问题中,由于Scan参数的类型为interface{},因此在database/sql方面,不会发生转换。发出query without args时,似乎驱动程序将使用文本协议,但是当查询有参数时,驱动程序将创建prepared-statement然后使用<与服务器通信< em>二进制协议。简而言之:

    1. 查询无参数:文本协议→结果[]byte→结果扫描到interface{}→结果返回为123456的ASCII代码(即{{ 1}})。
    2. 使用args查询:二进制协议→基于列类型([49 50 51 52 53 54])的转换→结果扫描到int64→结果返回为interface{}
    3. 如果要获得相同的结果,请使用以下代码进行第一次查询(为清楚起见,省略错误处理):

      int64