Golang操作MariaDB验证哈希时,为何需传递字节数组切片而非数组?
为什么在Go中需要用数组切片而非数组传递哈希值给MariaDB?
这问题我之前对接数据库时也踩过坑,其实核心原因是Go的database/sql包对固定大小数组和切片的处理逻辑完全不同,咱们一步步拆解:
1. 先搞清楚两种类型的本质差异
你用sha256.Sum256([]byte(token))生成的tokenHash是固定大小的数组类型[32]uint8——这是一个值类型,长度是编译期就确定的32,不能改变。而tokenHash[:]是把这个数组转换成了切片类型[]uint8(也就是[]byte,因为byte是uint8的别名),切片本质是一个包含指针、长度、容量的结构体,指向原数组的内存区域。
2. database/sql只认切片不认固定数组
Go的标准库database/sql在处理SQL参数时,依赖驱动实现的类型转换逻辑。对于数据库中的二进制数据(比如你存储的哈希值),驱动只接受[]byte(也就是[]uint8)类型的参数,因为:
- 切片是Go中用来表示可变长度字节序列的标准类型,和数据库中
BLOB或者二进制字符串的存储逻辑匹配; - 固定大小的数组
[32]uint8没有实现database/sql/driver.Valuer接口,驱动不知道怎么把它转换成数据库能识别的格式,所以直接抛出了unsupported type的错误。
3. 切片为什么能正常工作?
当你传递tokenHash[:]时,相当于告诉Go:“把这个固定数组当成一个可变长度的字节序列来用”。这个切片指向原数组的所有32个元素,类型是[]uint8,正好符合驱动的要求——驱动可以直接把这个切片的字节内容发送给MariaDB,和数据库中存储的t.token_hash字段(应该是二进制类型)做精确匹配。
再回顾你的代码对比
生成哈希的代码(返回固定数组)
// 这里tokenHash的类型是 [32]uint8 tokenHash := sha256.Sum256([]byte(token))
错误的参数传递(直接传数组)
// 报错:sql: converting argument $1 type: unsupported type [32]uint8, a array err := m.DB.QueryRowContext(ctx, query, tokenHash, time.Now())
正确的参数传递(传切片)
// tokenHash[:] 的类型是 []uint8,符合驱动要求 err := m.DB.QueryRowContext(ctx, query, tokenHash[:], time.Now())
你的SQL语句也没问题,是标准的关联查询:
SELECT u.id, u.first_name, u.last_name, u.email FROM users u INNER JOIN tokens t on (u.id = t.user_id) WHERE t.token_hash = ? and t.expiry > ?
内容的提问来源于stack exchange,提问作者Andrew Hojnowski
相关产品推荐
相关产品推荐

