MySQL 数据类型避坑指南:整形、字符串、日期及 JSON 的正确用法

前言

这篇文章,一起简单了解下~ mysql 整形、字符串类型、时间戳类型、JSON类型的使用场景和坑

整形的坑

整形分成很多种,TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT

类型 占用空间(字节) 值范围(signed) 值范围(unsigned)
TINYINT 1 -128~127 0~255
SMALLINT 2 -32768~32767 0~65535
MEDIUMINT 3 -838608~8388607 0~16777215
INT 4 -2147483638~2147483637 0~4294967295
BIGINT 8 -9223372036854775808~9223372036854775807 0~18446744073709551615

业务设计

  1. 不推荐使用整型类型的属性 Unsigned,若非要使用,参数 sql_mode 务必额外添加上选项 NO_UNSIGNED_SUBTRACTION

    • 因为 unsigned 和非unsigned 做操作,如果结果是负数,会报错
  2. 自增整型类型做主键,务必使用类型 BIGINT,而非 INT,后期表结构调整代价巨大;

  3. 自增整型回溯问题: MySQL 8.0 版本前,重启数据库会导致自增回溯,推荐字符串类型做主键

  4. 当达到自增到上限,再次自增插入,MySQL 数据库会报重复错误;

  5. 不要再使用浮点类型 Float、Double,MySQL 后续版本将不支持Float Double两种类型

  6. 账户余额字段,单位可以是分,设计是用整型类型,而不是 DECIMAL 类型,这样性能更好,存储更紧凑。因为DECIMAL 是个变长字段,会导致读取效率低空间碎片化两个问题

字符串类型

mysql 字符串的定义,包括字符长度类型(varchar/char)字符集(UTF8 UTF8MB4)排序规则 三部分组成。

VARCHAR 和CHAR

在 MySQL 数据库下,绝大部分场景使用类型 VARCHAR 就足够。CHAR是定长,VARCHAR是可变长度的

字符集

  1. 推荐字符集设置为 UTF8MB4,兼容emoji😯

排序规则

  1. utf8mb4_0900_ai_ci
  2. utf8mb4_0900_as_cs
  3. utf8mb4_bin

排序规则以 _ci 结尾,表示不区分大小写(Case Insentive),_cs 表示大小写敏感,_bin 表示通过存储字符的二进制进行比较。需要注意的是,比较 MySQL 字符串,默认采用不区分大小的排序规则

业务设计

有限状态列设计

一般业务会用tinyint,比如订单状态(待支付、支付中、支付完成、支付取消、已退款等)

但tinyint的缺点是,可能会被插入无效数据,不能准确的限制状态集合。

解决:

mysql5.6,可以用ENUM枚举类型去限制,但这个类型并不符合通用的mysql规范,其他DB没有,迁移时可能会有坑.

mysql8.0解决了这个问题,可以用CHECK约束状态集。

账户密码存储设计

重要!:密码不能明文在DB中存储 ,一般都需要加密后存储,但即使是md5这种单向加密,也是可能被暴力破解的。因此需要加动态salt值

好的密码设计 = 动态盐 + 非固定加密算法 $password格式:

密码设计 复制代码
$salt$cryption_algorithm$value(加密后的字符串)

动态salt,一般结合时间戳、随机数、用户信息去生成,也需要持久化到DB里.

日期类型字段设计

mysql常用的日期类型,是DATETimeTIMESTAMP

DATETIME

类型 DATETIME 最终展现的形式为:YYYY-MM-DD HH:MM:SS,固定占用 8 个字节。

我们可以在表上设置DATETIME,并保证update当前行时,自动更新日期

Mysql 复制代码
last_modify_date DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)

对应到Golang代码里,就是time.Time类型的字段:

Golang 复制代码
type Data struct{
    LastModifyDate time.Time `gorm:"last_modify_date"`
}

TIMESTAMP

TIMESTAMP也是时间类型,但他自带了时区信息。

TIMESTAMP的坑:由于类型 TIMESTAMP 占用 4 个字节,因此其存储的时间上限只能到'2038-01-19 03:14:07'。

业务选型:DATETIMETIMESTAMPINT

建议使用DATETIME

  • MySQL 5.6 版本开始 DATETIME 和 TIMESTAMP 精度支持到毫秒;
  • DATETIME 占用 8 个字节,TIMESTAMP 占用 4 个字节,DATETIME(6) 依然占用 8 个字节,TIMESTAMP(6) 占用 7 个字节;
  • TIMESTAMP 日期存储的上限为 2038-01-19 03:14:07,业务用 TIMESTAMP 存在风险;
  • 推荐日期类型使用 DATETIME,而不是 TIMESTAMP 和 INT 类型;
  • 表结构设计时,每个核心业务表,推荐设计一个 last_modify_date 的字段,用以记录每条记录的最后修改时间。

JSON字段设计

在关系存储中,有一些非结构化的数据,虽然也可以按照关系型去存储,但可能会导致两个问题:

  1. 数据非常稀疏
  2. 可扩展性差

比如这样的JSON:

json 复制代码
{
    "qq_number":123
    "wx_number":123
    ...
    "xx_number"
}

数据稀疏问题:比如用户绑定了qq、微信、微博等平台,实际业务允许只绑定任意一个.大部分列就会是空的,数据稀疏

扩展性差:如果现在要扩一个新平台字段,再增加一列,还需要修改表结构

这时候JSON的好处就体现了. 可以既不修改表结构,又解决数据稀疏的问题。

JSON字段使用总结

JSON 类型是 MySQL 5.7 版本新增的数据类型

  • 使用 JSON 数据类型,需要用 MySQL 8.0.17 以上的版本,性能更好,同时也支持 Multi-Valued Indexes,即一列里存储多种值,可以根据单个值索引;
  • JSON 数据类型的好处是无须预先定义列;
  • 不要将有明显关系型的数据用 JSON 存储,如用户余额、用户姓名、用户身份证等,这些都是每个用户必须包含的数据;
  • JSON 数据类型推荐使用在不经常更新的静态数据存储。
相关推荐
JohnYan1 小时前
Bun技术评估 - 03 HTTP Server
javascript·后端·bun
周末程序猿1 小时前
Linux高性能网络编程十谈|C++11实现22种高并发模型
后端·面试
ZHOU_WUYI1 小时前
Flask与Celery 项目应用(shared_task使用)
后端·python·flask
冒泡的肥皂2 小时前
强大的ANTLR4语法解析器入门demo
后端·搜索引擎·编程语言
IT_陈寒2 小时前
Element Plus 2.10.0 重磅发布!新增Splitter组件
前端·人工智能·后端
有梦想的攻城狮3 小时前
spring中的@RabbitListener注解详解
java·后端·spring·rabbitlistener
Java水解3 小时前
MySQL DQL全面解析:从入门到精通
后端·mysql
Aurora_NeAr3 小时前
Apache Spark详解
大数据·后端·spark
程序员岳焱3 小时前
Java 程序员成长记(二):菜鸟入职之 MyBatis XML「陷阱」
java·后端·程序员
hello早上好3 小时前
BeanFactory 实现
后端·spring·架构