今天我和我的同事注意到一件奇怪的事情。如果我们这样做。
select id from table
如果我们这样做: id
是 integer
,那么结果集就包含了整数的ID。一切都很好。然而当我们这样做时。
select 1
那么结果集就包含了字符串 "1"
. 导致这种情况的实际情况更加复杂,涉及到 ifnull()
,然而这是最简单的事情,重现了这个问题。
我们使用的是NodeJS(+Typescript)和TypeORM,如果这很重要的话。我记得我在PHP中也注意到了类似的事情,但是由于PHP对类型非常宽松,所以我并没有太在意。然而这次我们要把数据以JSON的形式传给外部系统,所以现在我们需要在其中添加 parseInt()
以便将字符串输入的数字转换为实际数字。
但是--wtf?为什么会出现这种行为?
WHERE id = 123 -- fine
WHERE id = "123" -- also fine; the string is converted to a number
WHERE text = "123" -- also fine (assuming `text` is VARCHAR or TEXT)
WHERE text = 123 -- inefficient because it converts each text to numeric
很多API都会把值 "绑定 "到查询中。 其中很多盲目的引用东西,不管目标是什么。 注意,上面的东西说引用总是 "很好 "的。
所以,我想这就是你问的 "为什么"。
而且,正如你所说,PHP、Perl等解释语言在这里有点占了上风。
我找到了答案。
原来MySQL将数字字面解释为64位整数。当做一个 CAST(xxx as integer)
它也将其作为64位整数处理(你不能指定为 tinyint
有)等。所以到了NodeJS的时候,它就会附带一个标签为 Int64
. 然而如果你直接选择一个DB列,那么你会得到一个更合理的 Int32
或什么的。
第二部分毕竟隐藏在MySQL客户端中。默认的 mysql
NPM包的作用是检查一个叫做 "连接 "的设置。bigNumberStrings
也就是 true
默认情况下,它将64位整数作为字符串保存。如果为真,则会将64位整数作为字符串保存。原因很明显--Javascript的 number
类型是一个64位浮点值,而这比64位整数要小。所以保持它为字符串,在所有情况下都能保持保真度。
另一方面,如果 bigNumberStrings=false
然后它试图将该值转换为一个 number
而只有在太大的情况下才会把它作为一串。这一点还挺好的,但又不一定一致,所以--小心处理。
我得想想我想采取哪种方案。