被 go 语言的 json.Marshal 恶心到了

201 天前
 qW7bo2FbzbC0

我的需求是,输入 sql ,返回序列化后的 json 结果。

在 python 中,官方库就可以返回[{'col1': 1, 'col2': '2', 'col3': true}....] 这种带类型的 json 结果。

在 go 中如果已知 sql 返回的列数和列类型,也可以构造一个 struct 进行数据映射,然后用json.Marshal转为 json 。

如果 sql 返回的列数和行类型未知,就很难受了,在 go/mysql 的官方 wiki 案例 中对于匿名的结果,使用了 interface 或者 sql.RawBytes ,但这两种替代方式在json.Marshal后都变成了 base64 encode 后的 string ,既丢失了类型也变异了结果( https://stackoverflow.com/questions/32501784/the-sqlx-library-gives-weird-base64-encoded-looking-results)

请问各位在实际业务中遇到这个问题是怎么处理的?

在其他语言中很自然的 object 序列化为原类型,在 go 的 json.Marshal 中怎么就全变成 string 了

13258 次点击
所在节点    Go 编程语言
131 条回复
james122333
200 天前
@lesismal

我目前弄的只有简单的 crud 和建立表 join 没整其他指令也没整 还是基於 sqlx 整的 只是用原生的 sql 应该也都差不多
根据 struct 中 tag 讯息拼接字符串 反射方法都已经写好 验证下来没问题 会这样搞主要是想偷懒点
fregie
200 天前
@qW7bo2FbzbC0 嫌麻烦而想放弃,这不是犯懒?
gowk
200 天前
回帖不支持代码,,看着就非常难受!
zzhaolei
200 天前
show me the code
lloovve
200 天前
这边建议转 rust 试试
woodfizky
200 天前
Python 是强类型语言,不管用 ORM 还是原生 SQL 一样要处理类型问题。

不懂某些评论为什么要说有 Python 味,吐槽之前好好调查一下再给出观点很难是吗?
zzhaolei
200 天前
@lesismal
“1. orm 是非常不好的选择, 中小项目倒是还可以, 大项目大数据量的, 用 orm 存在一些不确定性可能导致性能风险, 所以我都是禁止团队试用 golang orm 的”

这一点可以举例说明:有哪些不确定性可能导致性能风险吗

我现在在公司用的就是 GORM ,想了解一下
knva
200 天前
go 的 sql set 0 的问题太带劲了
qW7bo2FbzbC0
200 天前
@fregie 你满意就好
boqiqita
200 天前
幸好不会用 java 、C#、C 、C++
XyIsMy
200 天前
@zzhaolei @lesismal grom 可以设置 Logger level 在开发过程中就可以看到执行的 sql ,有问题能直接发现。gorm 也有 raw sql 模式可以直接用。
是在使用 GROM 中踩了哪些坑么。如果有坑的话,我需要重新考虑下要不要用 gorm
picone
200 天前
Go 使用 json.RawMessage 也可以达到你说的效果,不会变成 base64
zzhaolei
200 天前
@XyIsMy 我是这么用的。

我就是好奇,这些人张嘴闭嘴就是 ORM 有不确定性,到底有什么不确定性,自己测试过?还是踩过坑?还是说嘴一张一闭反正我不管,ORM 就是有性能问题?

我之前进行过性能测试,如果 GORM 那些事务什么的全都关了,是会比原生 SQL 慢一些,但是没有慢特别多。至今没有踩过什么坑。
james122333
200 天前
@zzhaolei

orm 本身没有不确定性 本质还是产生 query string 传参 orm 的不确定性在於框架的实现 太过细节的框架从另外角度讲是坑
gorm 确实是慢没错 更何况就是要用事务
我离职了再写一个比较好的自己用
qW7bo2FbzbC0
200 天前
各位,我比对了下,[]interface{}没有被 json.Marshal 出正确的数值和类型,是与我用的 go-mysql-driver 版本有关。

1.6.0 版本是出现了与我预测不同的结果。1.8 版本出现了预测的结果

json.Marshal 可能与本次贴文无直接关系。

另外,我觉得问题出自 json.Marshal 是从这个 sof 链接中的评论得到的错误推论,的确有迷惑性( https://stackoverflow.com/questions/34089750/marshal-byte-to-json-giving-a-strange-string)


```
This is because some idiot Millennial at Google decided it. Breaking the behaviour the RFC their JSON impl claims to follow defines. Check stackoverflow.com/a/78662958/3768429 for details.
```

该文指出 json.Marshal 处理 uint8[]时,错误输出了文字, 验证代码如下
```
func main() {
var x = []uint8{1, 2, 3, 4, 5, 6}
var y = []int8{1, 2, 3, 4, 5, 6}
xBytes, err := json.Marshal(x)
if err != nil {
panic(err)
}
yBytes, err := json.Marshal(y)
if err != nil {
panic(err)
}
fmt.Println(fmt.Sprintf("uint8 %s, int8: %s", string(xBytes), string(yBytes)))
}
```
输出的结果为
```
uint8 "AQIDBAUG", int8: [1,2,3,4,5,6]
```

https://go.dev/play/p/KGNG6voRuDk
sagaxu
200 天前
@zzhaolei @XyIsMy

ORM 的不确定性往往不是出自 ORM 本身,而是使用者的不确定性,大部分人只是会用,并不全面了解,有些时候会遇到令人惊讶的特性,其中不少人会专门写踩坑博文。
qW7bo2FbzbC0
200 天前
@james122333 您是对的,这的确和 json.Marshal 没关系,是 go-mysql-driver 的问题。

https://github.com/go-sql-driver/mysql/pull/1424
james122333
200 天前
@qW7bo2FbzbC0

vczyh 先讲这问题的 后面才看到 你要先感谢他
james122333
200 天前
@qW7bo2FbzbC0

我有跳转过去 go 底层看就是 基本类型应该都有函盖才对 所以推测 driver 问题 不过没验过 对照一下 vczyh 的说明应该是这样
ClericPy
200 天前
以前是用别的语言的吧,我记得有个库可以用比原生的优雅一点,不习惯的话要不要问问别人怎么用的再来吐槽

话说对于 JSON 解析如果没啥特殊需求,大多数语言都有 jmespath 的分支吧,以前用 py 的版本发现性能秒杀同类 jsonpath/objectpath 而且语法也简单,没必要自己硬抠嵌套结构,json-handler 一开直接提取路径了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/1057942

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX