大家好,我是你们的数据库学习伙伴。今天是MySQL系列教程的第2天,我们将深入探讨MySQL的数据类型。选错数据类型可能会导致数据丢失、性能下降甚至系统崩溃,所以这一课非常重要!

文章目录
-
- 一、为什么数据类型很重要
-
- [1.1 一个真实的踩坑案例](#1.1 一个真实的踩坑案例)
- [1.2 选错数据类型的后果](#1.2 选错数据类型的后果)
- 二、数值类型详解
-
- [2.1 整数类型](#2.1 整数类型)
- [2.2 浮点类型与定点类型](#2.2 浮点类型与定点类型)
- 三、字符串类型详解
-
- [3.1 CHAR vs VARCHAR](#3.1 CHAR vs VARCHAR)
- [3.2 TEXT与BLOB类型](#3.2 TEXT与BLOB类型)
- 四、日期时间类型详解
-
- [4.1 五种日期时间类型对比](#4.1 五种日期时间类型对比)
- [4.2 踩坑:TIMESTAMP的2038年问题](#4.2 踩坑:TIMESTAMP的2038年问题)
- [五、JSON类型(MySQL 5.7+)](#五、JSON类型(MySQL 5.7+))
- 六、数据类型选择最佳实践
-
- [6.1 经验总结表](#6.1 经验总结表)
- [6.2 设计原则](#6.2 设计原则)
- 七、面试高频考点
- 八、总结
- 九、下一步预告
- 十、参考资料
- 互动话题
一、为什么数据类型很重要
1.1 一个真实的踩坑案例
在存储商品价格时使用 FLOAT 类型:
sql
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
price FLOAT -- 错误的选择!
);
当计算订单金额时,出现了这样的情况:
sql
INSERT INTO products (name, price) VALUES ('iPhone 15', 5999.99);
SELECT * FROM products;
-- 结果:5999.989990234375
0.01元的误差,在财务系统中是不可接受的!这就是浮点数精度问题导致的悲剧。
1.2 选错数据类型的后果
| 问题类型 | 具体表现 | 影响程度 |
|---|---|---|
| 数据丢失 | TINYINT存储大数导致溢出 | 严重 |
| 精度问题 | FLOAT/DOUBLE存储金额 | 严重 |
| 性能下降 | 使用过大的数据类型 | 中等 |
| 存储浪费 | VARCHAR(500)存短文本 | 轻微 |
| 兼容性问题 | TIMESTAMP的2038年限制 | 严重 |
二、数值类型详解
2.1 整数类型
MySQL提供了5种整数类型,它们的区别主要在于取值范围和存储空间:
| 类型 | 存储空间 | 有符号范围 | 无符号范围 | 适用场景 |
|---|---|---|---|---|
| TINYINT | 1字节 | -128 ~ 127 | 0 ~ 255 | 状态、布尔值 |
| SMALLINT | 2字节 | -32768 ~ 32767 | 0 ~ 65535 | 小范围计数 |
| MEDIUMINT | 3字节 | -8388608 ~ 8388607 | 0 ~ 16777215 | 中等范围ID |
| INT | 4字节 | -21亿 ~ 21亿 | 0 ~ 43亿 | 主键ID、计数 |
| BIGINT | 8字节 | 极大范围 | 极大范围 | 分布式ID、大数 |
经验之谈:
- 状态字段用
TINYINT(如:0-禁用,1-启用) - 主键ID用
INT UNSIGNED AUTO_INCREMENT - 用户ID如果可能超过21亿,用
BIGINT
sql
-- 用户表设计示例
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
status TINYINT UNSIGNED DEFAULT 1 COMMENT '0-禁用 1-启用',
age TINYINT UNSIGNED COMMENT '年龄,0-255足够',
login_count INT UNSIGNED DEFAULT 0
);
2.2 浮点类型与定点类型
| 类型 | 存储空间 | 精度 | 适用场景 | 注意事项 |
|---|---|---|---|---|
| FLOAT | 4字节 | 约7位 | 科学计算 | 有精度损失 |
| DOUBLE | 8字节 | 约15位 | 科学计算 | 有精度损失 |
| DECIMAL | 变长 | 自定义 | 金额计算 | 精确计算 |
重点:DECIMAL用于金额
sql
-- 正确的金额存储方式
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
total_amount DECIMAL(10, 2) COMMENT '总金额,整数8位+小数2位',
discount DECIMAL(10, 2) DEFAULT 0.00
);
-- DECIMAL(M, D) 说明:
-- M:总位数(精度),最大65
-- D:小数位数(标度),最大30
-- DECIMAL(10, 2) 可以存储:-99999999.99 到 99999999.99
踩坑提醒: 永远不要使用FLOAT或DOUBLE存储金额!银行、电商、支付系统必须使用DECIMAL。
三、字符串类型详解
3.1 CHAR vs VARCHAR
这是面试中最常问的问题之一:
| 特性 | CHAR | VARCHAR |
|---|---|---|
| 存储方式 | 固定长度 | 变长 |
| 存储空间 | 始终占用定义长度 | 实际长度+1~2字节 |
| 性能 | 更快(无长度计算) | 稍慢 |
| 适用场景 | 固定长度数据 | 变长数据 |
| 最大长度 | 255字符 | 65535字节 |
sql
-- CHAR适合存储固定长度的数据
CREATE TABLE users (
phone CHAR(11) COMMENT '手机号,固定11位',
id_card CHAR(18) COMMENT '身份证号,固定18位',
gender CHAR(1) COMMENT '性别 M/F'
);
-- VARCHAR适合存储变长数据
CREATE TABLE articles (
title VARCHAR(200) COMMENT '标题,长度不固定',
summary VARCHAR(500) COMMENT '摘要'
);
经验之谈:
- 手机号、身份证号、固定编码用
CHAR - 用户名、标题、地址用
VARCHAR - 长度限制要合理,不要为了省事都设255
3.2 TEXT与BLOB类型
| 类型 | 最大长度 | 存储方式 | 适用场景 |
|---|---|---|---|
| TINYTEXT | 255字节 | 外部存储 | 短文本 |
| TEXT | 64KB | 外部存储 | 文章内容 |
| MEDIUMTEXT | 16MB | 外部存储 | 长文章 |
| LONGTEXT | 4GB | 外部存储 | 大文本 |
| TINYBLOB | 255字节 | 外部存储 | 小二进制 |
| BLOB | 64KB | 外部存储 | 图片、文件 |
| MEDIUMBLOB | 16MB | 外部存储 | 较大文件 |
| LONGBLOB | 4GB | 外部存储 | 大文件 |
踩坑提醒:
- TEXT/BLOB类型不能设置默认值
- 查询时不会加载到内存,性能较差
- 大文件建议存对象存储(OSS/S3),数据库只存URL
sql
-- 文章表设计
CREATE TABLE articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
content TEXT COMMENT '正文内容',
cover_image VARCHAR(500) COMMENT '封面图URL,不是存图片本身'
);
四、日期时间类型详解
4.1 五种日期时间类型对比
| 类型 | 格式 | 范围 | 存储空间 | 适用场景 |
|---|---|---|---|---|
| DATE | YYYY-MM-DD | 1000-01-01 ~ 9999-12-31 | 3字节 | 生日、纪念日 |
| TIME | HH:MM:SS | -838:59:59 ~ 838:59:59 | 3字节 | 持续时间 |
| YEAR | YYYY | 1901 ~ 2155 | 1字节 | 年份 |
| DATETIME | YYYY-MM-DD HH:MM:SS | 1000-01-01 ~ 9999-12-31 | 8字节 | 通用时间 |
| TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970-01-01 ~ 2038-01-19 | 4字节 | 记录时间戳 |
sql
CREATE TABLE events (
id INT PRIMARY KEY AUTO_INCREMENT,
event_date DATE COMMENT '活动日期',
start_time TIME COMMENT '开始时间',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
4.2 踩坑:TIMESTAMP的2038年问题
这是MySQL中一个著名的时间炸弹!
TIMESTAMP使用4字节存储,最大只能表示到 2038-01-19 03:14:07 UTC。
sql
-- 这个插入在2038年后会失败!
INSERT INTO events (created_at) VALUES ('2040-01-01 00:00:00');
-- ERROR 1292 (22007): Incorrect datetime value
解决方案:
- 使用
DATETIME代替TIMESTAMP - 升级到MySQL 8.0,使用
DATETIME(6)支持微秒
经验之谈:
- 记录创建/更新时间用
TIMESTAMP(自动时区转换) - 需要存储未来时间(如预约)用
DATETIME - 生日、历史日期用
DATE
五、JSON类型(MySQL 5.7+)
MySQL 5.7开始原生支持JSON类型,可以存储和查询JSON数据。
sql
-- 存储商品规格(不同商品规格不同)
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
specs JSON COMMENT '商品规格,JSON格式'
);
-- 插入JSON数据
INSERT INTO products (name, specs) VALUES
('iPhone 15', '{"color": "黑色", "storage": "256GB", "screen": "6.1英寸"}'),
('MacBook Pro', '{"color": "银色", "cpu": "M3", "ram": "16GB"}');
-- 查询JSON字段
SELECT * FROM products WHERE JSON_EXTRACT(specs, '$.color') = '黑色';
-- 或使用 -> 运算符
SELECT specs->>'$.storage' FROM products WHERE id = 1;
JSON类型的优势:
- 自动验证JSON格式
- 支持索引(通过虚拟列)
- 支持JSON函数查询
经验之谈:
- 适合存储不固定的属性(如商品规格、用户配置)
- 不要滥用,固定字段还是建议用列存储
- 频繁查询的JSON字段建议创建虚拟列索引
六、数据类型选择最佳实践
6.1 经验总结表
| 数据场景 | 推荐类型 | 说明 |
|---|---|---|
| 主键ID | INT UNSIGNED / BIGINT | 根据数据量选择 |
| 状态/枚举 | TINYINT | 0-禁用,1-启用 |
| 金额 | DECIMAL(10,2) | 精确计算 |
| 手机号 | CHAR(11) | 固定长度 |
| 邮箱 | VARCHAR(100) | 长度可变 |
| 短文本 | VARCHAR(255) | 标题、名称 |
| 长文本 | TEXT | 文章内容 |
| 日期 | DATE | 生日、纪念日 |
| 时间戳 | TIMESTAMP/DATETIME | 记录时间 |
| JSON数据 | JSON | 灵活属性 |
6.2 设计原则
- 最小够用原则:选择满足需求的最小类型
- 精确优先原则:金额用DECIMAL,不用浮点数
- 固定优先原则:固定长度用CHAR,变长用VARCHAR
- 简单优先原则:能用简单类型不用复杂类型
七、面试高频考点
考点1:INT(11)的11是什么意思?
答案: INT(11)中的11只是显示宽度,与存储范围无关。INT始终占用4字节。
sql
-- INT(11) 和 INT(3) 存储范围完全相同
-- 11只在配合 ZEROFILL 时有视觉效果
CREATE TABLE test (
num1 INT(5) ZEROFILL,
num2 INT
);
INSERT INTO test VALUES (123, 123);
-- num1显示:00123
-- num2显示:123
考点2:VARCHAR(255)和VARCHAR(100)的区别?
答案:
- 存储长度小于255时,VARCHAR需要1字节存储长度;超过255需要2字节
- VARCHAR(100)和VARCHAR(255)存储'hello'占用空间相同
- 但VARCHAR(255)可能让开发者放松警惕,存储过长的数据
- 建议:根据实际业务需求设置合理长度
考点3:CHAR和VARCHAR的区别?
答案:
- CHAR固定长度,VARCHAR变长
- CHAR性能稍好,VARCHAR节省空间
- CHAR最大255字符,VARCHAR最大65535字节
- 存储长度固定用CHAR(如手机号),变长用VARCHAR
考点4:为什么金额不能用FLOAT/DOUBLE?
答案: 浮点数使用二进制存储小数,无法精确表示某些十进制小数(如0.1),会导致精度丢失。财务计算必须使用DECIMAL。
八、总结
今天我们学习了MySQL的主要数据类型:
- 数值类型:TINYINT/INT/BIGINT用于整数,DECIMAL用于金额
- 字符串类型:CHAR固定长度,VARCHAR变长,TEXT存大文本
- 日期时间:DATE/DATETIME/TIMESTAMP各有适用场景
- JSON类型:灵活存储非结构化数据
记住三个原则:最小够用、精确优先、简单优先。
九、下一步预告
Day3:MySQL基础SQL语句
我们将学习:
- DDL语句:CREATE、DROP、ALTER
- DML语句:INSERT、UPDATE、DELETE
- DQL语句:SELECT基础查询
- 实战:创建电商订单系统相关表
十、参考资料
互动话题
你在工作中遇到过哪些数据类型相关的坑?欢迎在评论区分享:
- 你是否曾经用FLOAT存过金额?后来怎么解决的?
- 你们项目中主键ID用INT还是BIGINT?为什么?
- 对于TIMESTAMP的2038年问题,你们是怎么处理的?
点赞+收藏+关注,学习MySQL不迷路!我们Day3见!