如何在MySQL中存储二进制数据?

huangapple go评论103阅读模式
英文:

How can I store binary data in MySQL?

问题

我正在使用来自http://github.com/go-sql-driver/mysql的MySQL驱动程序。

我需要将IP地址的二进制表示存储在MySQL的BINARY(4)列中。

为了做到这一点,我尝试了以下代码:

    startSlice := net.ParseIP(rangeStart).To4()
    var startBytes [4]byte
    copy(startSlice[:], startBytes[0:4])

    endSlice := net.ParseIP(rangeEnd).To4()
    var endBytes [4]byte
    copy(endSlice[:], endBytes[0:4])

    r, e := db.Exec("UPDATE AIPRangesBlocks SET BinRangeStart = ?, BinRangeEnd = ? WHERE IPGRID = ?", startBytes, endBytes, id)
    fmt.Println("result of update:", r)
    if e != nil {
        fmt.Println(e)
    }

请注意,我使用了copy命令将[]byte切片转换为[4]byte数组,但是我遇到了以下错误:

sql: 转换执行参数#0的类型:不支持的类型[4]uint8,一个数组

如果我直接使用net.ParseIP("some_ip").To4(),我会遇到以下错误:

sql: 转换执行参数#0的类型:不支持的类型net.IP,一个切片

我该如何发送二进制数据?

如果我使用十六进制字符串,它会执行查询,但是在检索时我得不到正确的值。

我尝试了hex.EncodeToString()和"0x" + hex.EncodeToString(),但都没有正常工作。

这是一个示例:

66.182.64.0 变成 42b64000

如果我将"42b64000"存储在我的MySQL列中,我得到:

52 50 98 54

如果我将"0x42b64000"存储在我的MySQL列中,我得到:

48 120 52 50

我该如何解决这个问题?

英文:

I'm using the MySQL driver from http://github.com/go-sql-driver/mysql

I need to store the binary representation of an IP address in MySQL in a BINARY(4) column.

To do this, I've tried:

    startSlice := net.ParseIP(rangeStart).To4()
    var startBytes [4]byte
    copy(startSlice[:], startBytes[0:4])

    endSlice := net.ParseIP(rangeEnd).To4()
    var endBytes [4]byte
    copy(endSlice[:], endBytes[0:4])

    r, e := db.Exec("UPDATE AIPRangesBlocks SET BinRangeStart = ?, BinRangeEnd = ? WHERE IPGRID = ?", startBytes, endBytes, id)
    fmt.Println("result of update:", r)
    if e != nil {
        fmt.Println(e)
    }

Note that I used the copy command to convert from a []byte slice to simply a [4]byte array, but I get this error:

sql: converting Exec argument #0's type: unsupported type [4]uint8, a array

If I do it directly as net.ParseIP("some_ip").To4(), I get this error:

sql: converting Exec argument #0's type: unsupported type net.IP, a slice

How do I send the binary data?

If I use a hexadecimal string, it will execute the query, but I'm not getting the right values on retrieval.

I tried hex.EncodeToString() and "0x" + hex.EncodeToString() and neither are working properly.

Here's an example:

66.182.64.0 becomes 42b64000

If I store "42b64000" in my MySQL column, I get back:

52 50 98 54

If I store "0x42b64000" in my MySQL column, I get back:

48 120 52 50

How do I fix this?

答案1

得分: 1

如果你将"42b64000"存储在我的MySQL列中,你会得到:

52 50 98 54

解码成ASCII码后,这是你给出的字符串的开头,例如

"42b6"

这表明将IP地址片段作为字符串传递将起作用,例如

startSlice := net.ParseIP(rangeStart).To4()
endSlice := net.ParseIP(rangeEnd).To4()
r, e := db.Exec("UPDATE AIPRangesBlocks SET BinRangeStart = ?, BinRangeEnd = ? WHERE IPGRID = ?", string(startSlice), string(endSlice), id)
fmt.Println("更新结果:", r)
if e != nil {
    fmt.Println(e)
}

在Go语言中,字符串本质上是[]byte的只读版本,你可以在它们之间进行转换而没有问题(除了一些内存复制)。希望MySQL驱动程序中的引号可以处理字符串中的NUL字符。

英文:

If you store "42b64000" in my MySQL column, you get back:

52 50 98 54

Decoded into ASCII this is the start of the string which you gave it, eg

"42b6"

Which suggest that passing the IP address slice as a string will work, eg

startSlice := net.ParseIP(rangeStart).To4()
endSlice := net.ParseIP(rangeEnd).To4()
r, e := db.Exec("UPDATE AIPRangesBlocks SET BinRangeStart = ?, BinRangeEnd = ? WHERE IPGRID = ?", string(startSlice), string(endSlice), id)
fmt.Println("result of update:", r)
if e != nil {
    fmt.Println(e)
}

In go strings are essentially a read only version of []byte and you can cast between them with no problems (other than a bit of memory copying). Hopefully the quoting in the MySQL driver can deal with NULs in the string.

答案2

得分: 1

你可以尝试使用encoding/binary将其存储为uint32类型:binary.LittleEndian.Uint32(net.ParseIP(rangeStart).To4()),以及binary.LittleEndian.PutUint32(destinationSlice, colValue)
如果LittleEndian对你的其他应用程序产生错误的结果,可以改用BigEndian

英文:

You could try to store it as an uint32 with encoding/binary: binary.LittleEndian.Uint32(net.ParseIP(rangeStart).To4())
and binary.LittleEndian.PutUint32(destinationSlice, colValue).
If LittleEndian gives the wrong results for your other applications, use BigEndian instead.

答案3

得分: 0

你是对的,直到将其转换为十六进制字符串的部分。

以下是我解决这个问题的方法(适用于IPv4和IPv6):

  1. 假设你的表是:

    CREATE TABLE ip_addr (ip VARBINARY(16));

  2. 准备INSERT或UPDATE语句如下:

    stmt := db.Prepare("INSERT INTO ip_addr (ip) VALUES (UNHEX(?))")

  3. 在Go代码中:

    if ip.To4() != nil {
    ip_hex = hex.EncodeToString(ip.To4())
    } else {
    ip_hex = hex.EncodeToString(ip.To16())
    }
    stmt.Exec(ip_hex)

英文:

You are right upto the part of converting it to HEX string.

Here is how I solved it (for both IPv4 and IPv6):

  1. Assume that your table is:

> CREATE TABLE ip_addr (ip VARBINARY(16));

  1. Prepare the INSERT or UPDATE statement as follows:

> stmt := db.Prepare("INSERT INTO ip_addr (ip) VALUES (UNHEX(?))")

  1. In the 'Go' code:

> if ip.To4() != nil {
> ip_hex = hex.EncodeToString(ip.To4())
> } else {
> ip_hex = hex.EncodeToString(ip.To16())
> }
> stmt.Exec(ip_hex)

huangapple
  • 本文由 发表于 2013年11月10日 14:23:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/19886919.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定