1. 字符和字节的含义:
-
字符:
字符是一种符号,同字节说的存储单位不是一回事,例如,一个中文字、一个英文字母、一个中文或者英文标点符号。
1字节 = 8位
1字符 = 3字节 (UTF-8); -
字节:
我们知道,电脑只能用高电位、低电位的形式存储数据,抽象出来,那就是电脑存数据最终只能用二进制的形式,也就是用0和1表示,无论任何数据,最终存储的时候都是一段包含多个0和1的串,例如“00110101”,这里的每一个0或1被称为1位。“位”就是最小的存储单位,然后我们把8位称为1个字节,也就是1个字节等于8位。由于二进制实在太长,不方便展示,所以一般将1个字节(8位)的二进制转换成十六进制进行展示,例如将11010011转换成十六进制就是D3,这就是一个字节。
我们没有办法直接在电脑里面存入字符,例如你没有办法将“你好世界”这四个字进行存储,现行的方案是将字符编码成0和1数字串的形式,两者建立映射关系。例如你可以用“1”表示“你”,用“10”表“好”,用“101”表示“世”,用“111”表示“界”。反过来讲,如果你发现磁盘某一段地方存了“101”,那你就知道这里代表着“世”这个中文字。
我们把类似以上的这种方案叫做“字符集”。我们在使用MySQL时,最常用的字符集就是 UTF-8 。这个字符集和上面说的这个方案没有本质区别,只是建立映射关系不同而已。(1) 我们可以看下字符“你”在UTF-8字符集下的表示方式,在MySQL中你可以直接使用**HEX()**函数来进行转换。
SELECT HEX('你')
可以看出,使用UTF-8字符集,字符“你”需要使用三个字节来进行存储(分别是E4,BD,A0
),实际存储的二进制是111001001011110110100000
(2) 存储一个英文字符需要占用多少字节。
SELECT HEX('A')
可以看到,存储英文字符“Z”只需要一个字节。
(3) 在MySQL中,你可以直接使用LENGTH()函数来查看指定字符串占用的空间(字节数)。
字节数
SELECT LENGTH('你') -- 3
SELECT LENGTH('Z') -- 1
SELECT LENGTH('A啊a1') -- 6
2. mysql不同数据类型长度含义
- 字符串类型
常用的字符串类型的数据类型有 CHAR 和 VARCHAR 两种,两者后面都需要跟上一个数字表示长度,例如
CHAR(10)
VARCHAR(10)
CHAR(n) 和 VARCHAR(n) 两者中的 n 含义均为该字段最大可容纳的字符数。
-
整数类型
常用的整数数据类型有 tinyint ,smallint ,mediumint , int ,bigint 共计5种,在声明列时,后面也可以跟上 n ,例如 int(n) 。n代表的是显示宽度,长度的设定值范围1~255(设置0时自动转为11,不设置时自动转为默认的11)实际上这里的 n 非常鸡肋,几乎没有任何使用场景。它的含义是“显示位宽”,这个 n 无论填任何数,不影响存储环节,仅影响在检索时的输出格式,而且在非常严格的情况下才成立。
注意: 从MySQL 8.0.17开始,整数类型已经不推荐使用显示宽度,所以声明类型是建议不写。 -
浮点型
在mysql中,我们用【小数数据类型(最大位数,小数点右侧的位数)】来表示,如decimal(m,n)。m就是最大位数,n就是小数点后面的数字个数。需要注意的是这里的“位”是指十进制的数字的位数。float(m,n)、double(m,n) 含义差不多,都是定义长度和精度的。
更详细的可以参看博客: ⇒ Mysql5.7数据类型
3. mysql中float、double、decimal精度问题探讨
float和double在存取时因为精度不一致会发生丢失,不能盲目的说float和double精度可能丢失。具体原因如下:
没有设置精度位数
。没有设置精度就是使用默认的精度, 此时的策略就是,尽可能保证精度,因此一般使用最高精度存储数据的。如果设置数据类型指定了精度,那么存储数据时就按照设置的精度来存储。例如,6.214522存入6位小数的float和double是不会丢失小数精度的,取出来的数还是6.214522。也就是说,一个小数存入相同的精度的数据类型时,精度是不会丢失的。设置的精度和存储时的精度不一致
。当7或更多位精度的数字存入6位精度类型字段时,会发生什么?结果会发生四舍五入。四舍五入的结果就是匹配字段的数据类型的精度长度。此时精度也会丢失。不管内部如何处理,我们得到的数据是经过四舍五入的。但是有一点可以确定,我们在读取取舍后的数字时,是固定的。虽然浮点数存储的不是确切的数值,但是在你指定的精度长度条件下,存取都是确定的一个数值。而发生精度变化的就是数值的精度和字段的精度长度不匹配,从而发生数值扩展精度和截断精度问题,这也就是浮点数精度不准确的问题。mysql数据库使用其他数据库引擎来查询
.这个精度丢失的原因,就可能是不同的数据库引擎对浮点数的精度扩展和截断处理策略不一致,而且,存储时策略也不一致。所以导致精度会出现各种变化。这种问题也就是催生decimal类型的出现。我们前面看到的decimal是可以确切存储小数的精度的。因为在存储的时候会将小数以字符串存储,就不会再发生精度的扩展问题。但是decimal依然会发生精度截断问题。如果decimal指定精度为2位小数,存入的是这样的值:12.123,你觉得结果如何?当然还是会发生四舍五入。结果就是12.12,然而12.12以字符串形式存入了数据库。此后,12.12始终都是12.12,表现出来的是小数,然而内部是字符串形式存储,所以,小数精度不会再发生变化了。我们不管以什么精度来获取这个值,都是12.12,而且,不管是一般数据库引擎读取到的也都是12.12,所以decimal才是大家推荐使用的金额存储类型。
decimal的存储结果没有精度丢失问题。因为decimal内部以字符形式存储小数,属于准确存储。而float和double等则属于浮点数数字存储,所以没有办法做到准确,只能尽可能近似。这也是大家选用decimal的原因,也认为decimal精度不会丢失的原因。
知识拓展
- 二进制转十六进制:
-
首先呢,先要看看十六位数的表示方法,如图1所示。
-
再来掌握二进制数与十六进制数之间的对应关系表,如图2所示。只有牢牢掌握的对应关系,在转换的过程中才会事半功倍。
-
二进制转换成十六进制的方法是,取四合一法,即从二进制的小数点为分界点,向左(或向右)每四位取成一位,如图3所示。
-
组分好以后,对照二进制与十六进制数的对应表(如图2中所示),将四位二进制按权相加,得到的数就是一位十六进制数,然后按顺序排列,小数点的位置不变哦,最后得到的就是十六进制数哦,如图4所示。
-
注意16进制的表示法,用字母H后缀表示,比如BH就表示16进制数11;也可以用0X前缀表示,比如0X23就是16进制的23.直观表示法如图5所示。
-
这里需要注意的是,在向左(或向右)取四位时,取到最高位(最低位)如果无法凑足四位,就可以在小数点的最左边(或最右边)补0,进行换算,如图6所示。