为何MySQL指定FLOAT类型却实际存储为DOUBLE?
问题:MySQL FLOAT字段读取后变成DOUBLE精度?
我在MySQL中创建了如下表:
create table testfloat (f float unsigned); insert into testfloat values (70.99);
预期存储的是70.99的32位FLOAT等值,但用Go代码读取后,得到的却是64位DOUBLE的精度值。
使用的Go读取代码:
package main import ( "database/sql" "fmt" "strconv" _ "github.com/go-sql-driver/mysql" ) func main() { db, err := sql.Open("mysql", "root@(localhost)/test") if err != nil { panic(err) } rows, err := db.Query("select f from testfloat;") if err != nil { panic(err) } fmt.Printf("32-bit 70.99: %s\n", strconv.FormatFloat(70.99, 'f', 50, 32)) fmt.Printf("64-bit 70.99: %s\n", strconv.FormatFloat(70.99, 'f', 50, 64)) fmt.Printf("64-bit 70.99 cast from 32-bit 70.99: %s\n", strconv.FormatFloat(float64(float32(70.99)), 'f', 50, 64)) var f float64 for rows.Next() { if err := rows.Scan(&f); err != nil { panic(err) } fmt.Printf("DB 70.99: %.50f\n", f) } }
输出结果:
32-bit 70.99: 70.98999786376953125000000000000000000000000000000000 64-bit 70.99: 70.98999999999999488409230252727866172790527343750000 64-bit 70.99 cast from 32-bit 70.99: 70.98999786376953125000000000000000000000000000000000 DB 70.99: 70.98999999999999488409230252727866172790527343750000
实际读取的结果和64位DOUBLE的70.99一致,而非32位FLOAT的等值,这是为什么?
原因分析
MySQL协议的自动转换:MySQL在通过客户端协议返回FLOAT类型数据时,会自动将32位FLOAT转换为64位DOUBLE发送。这是协议的默认行为,目的是避免传输过程中出现额外精度损失,所以即使表中存的是32位FLOAT,客户端拿到的已经是转换后的DOUBLE值。
Go驱动的处理逻辑:go-sql-driver/mysql驱动接收MySQL返回的DOUBLE数据后,直接映射到Go的
float64类型,不会逆向转换回32位FLOAT。所以用float64接收时,得到的就是MySQL转换后的DOUBLE精度值。验证存储类型的方法:如果要确认数据库中确实存的是32位FLOAT,可以在MySQL命令行执行
SELECT f, HEX(f) FROM testfloat;,对比十六进制值:32位FLOAT的70.99对应十六进制428B3D71,而DOUBLE对应405279999999999A,就能确认存储类型没问题,只是传输时被转换了。
内容的提问来源于stack exchange,提问作者wingerse
相关产品推荐
相关产品推荐

