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 数据类型推荐使用在不经常更新的静态数据存储。
相关推荐
XW6 分钟前
个人图片分类-按照年分文件夹管理 python处理个人图片
后端
customer0823 分钟前
【开源免费】基于SpringBoot+Vue.JS电商应用系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Pandaconda24 分钟前
【后端开发面试题】每日 3 题(十五)
数据库·分布式·后端·python·面试·后端开发·幂等性
rookiefishs40 分钟前
如何nodejs中使用winston库记录本地日志?
前端·javascript·后端
Sendingab1 小时前
3.5 Spring Boot邮件服务:从基础发送到模板邮件进阶
spring boot·后端·python
uhakadotcom2 小时前
JDK 24新特性解读:提升性能、安全性和开发效率
后端·面试·github
盖世英雄酱581362 小时前
设计模式在Springboot都用在哪些地方呢
java·后端
逸风尊者2 小时前
开发易忽视的问题:内存溢出/泄漏案例
java·后端·面试
Emma歌小白2 小时前
在 Windows/Mac/Linux 上安装 Java(JDK)
java·后端
涡能增压发动积2 小时前
SpringAI-MCP技术初探
人工智能·后端·架构