常用数据类型
建表时每个字段都必须选择数据类型。
数据类型决定了:
- 这个字段能存什么值。
- 最大能存多大。
- 占用多少空间。
- 能不能排序、计算、比较。
- 数据库能不能帮你拦住明显错误的数据。
例如:
这句不是随便写的。
它表示:
age 是一个很小的非负整数,范围是 0 到 255
如果连范围都不知道,就很容易把字段类型选大、选小,或者选错。
一、整数类型
整数类型用来保存没有小数的数字。
MySQL 常见整数类型如下:
1. 什么是 UNSIGNED
默认情况下,整数类型是有符号的,也就是可以存负数。
TINYINT 的范围是:
如果加上 UNSIGNED,就表示无符号,不能存负数。
TINYINT UNSIGNED 的范围是:
年龄、浏览次数、库存、主键 ID 这类字段通常不应该是负数,所以一般会加 UNSIGNED。
2. 常见整数选型
示例:
CREATE TABLE number_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
age TINYINT UNSIGNED NULL,
view_count INT UNSIGNED NOT NULL DEFAULT 0,
stock INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
3. INT(11) 不是最大长度
很多人看到旧表结构里有:
容易误以为它表示最多存 11 位数字。
这是错的。
INT 的范围始终是:
INT(11) 里的 11 以前主要和显示宽度有关,不决定存储范围。MySQL 8 里整数显示宽度已经不推荐使用。
所以新建表时直接写:
不要写成:
二、小数类型
小数类型主要有:
1. 金额使用 DECIMAL
金额不要用 FLOAT 或 DOUBLE。
推荐:
price DECIMAL(10, 2) NOT NULL
DECIMAL(M, D) 的含义:
所以:
表示:
总共最多 10 位数字,其中小数点后 2 位,整数部分最多 8 位
它能保存的最大值类似:
常见金额写法:
price DECIMAL(10, 2) NOT NULL DEFAULT 0.00
订单金额更大时可以写:
total_amount DECIMAL(12, 2) NOT NULL DEFAULT 0.00
2. DECIMAL 的范围限制
MySQL 里 DECIMAL 的常见限制:
例如:
可以保存:
但是不能保存:
因为整数部分最多只有 3 位。
3. 为什么金额不用 FLOAT
FLOAT 和 DOUBLE 是近似值。
它们适合科学计算、坐标、比例这类场景,不适合保存订单金额。
例如金额需要精确到分:
浮点数在底层可能出现精度误差。
所以金额字段优先使用:
或者直接用整数保存分:
amount_cent BIGINT UNSIGNED NOT NULL DEFAULT 0
例如 1999 表示 19.99 元。
三、字符串类型
字符串类型用来保存文本。
常见类型:
注意:VARCHAR(n) 里的 n 是字符数,但表的一行数据总大小有限制。使用 utf8mb4 时,一个中文或 emoji 最多可能占 4 个字节。
1. CHAR 和 VARCHAR 的区别
CHAR(n) 是固定长度。
例如:
适合:
- 固定 6 位验证码。
- 固定长度编码。
- 固定长度性别标识。
VARCHAR(n) 是可变长度。
例如:
username VARCHAR(50) NOT NULL
适合:
大多数业务短文本优先用 VARCHAR。
2. 常见字符串选型
示例:
CREATE TABLE string_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
code CHAR(6) NOT NULL,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
bio VARCHAR(500) NULL,
content TEXT NULL,
PRIMARY KEY (id)
);
3. 手机号不要用整数
手机号看起来是数字,但它不是拿来做数学计算的。
手机号应该用字符串保存:
phone VARCHAR(20) NOT NULL
原因:
- 可能有国家区号,例如
+86。
- 可能有前导 0。
- 不需要加减乘除。
- 超长号码可能超过普通整数范围。
身份证号、银行卡号、邮政编码也一样,通常用字符串保存。
4. TEXT 不要乱用
短文本不要都用 TEXT。
例如用户名:
这就不合适。
用户名长度本来有限,应该写:
username VARCHAR(50) NOT NULL
简单原则:
- 长度明确、经常查询筛选的字段,用
VARCHAR。
- 内容可能很长的正文、备注、评论,用
TEXT。
四、日期和时间类型
日期时间类型用来保存日期、时间和时间戳。
常见类型:
1. DATETIME 和 TIMESTAMP 的区别
DATETIME 保存的是日期时间本身。
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
它更像是在保存:
TIMESTAMP 会受时区影响,MySQL 存储和读取时会做时区转换。
简单选择:
普通后端项目里,created_at、updated_at 常用 DATETIME。
2. 创建时间和更新时间
常见写法:
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
含义:
示例:
CREATE TABLE time_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
3. 生日字段不要用 DATETIME
生日只需要日期,不需要时分秒。
推荐:
不要写成:
除非业务确实需要具体出生时间。
五、布尔值怎么存
MySQL 没有真正独立的布尔存储类型。
BOOLEAN 和 BOOL 在 MySQL 里本质上是 TINYINT(1) 的别名。
常见写法:
is_deleted TINYINT UNSIGNED NOT NULL DEFAULT 0
约定:
例如:
CREATE TABLE boolean_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
is_deleted TINYINT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
如果想限制只能是 0 或 1,可以加检查约束:
CONSTRAINT chk_boolean_demo_is_deleted CHECK (is_deleted IN (0, 1))
六、枚举类型 ENUM
ENUM 表示字段只能从固定值里选一个。
语法:
字段名 ENUM('值1', '值2', '值3')
例如文章状态:
status ENUM('draft', 'published', 'archived') NOT NULL DEFAULT 'draft'
这表示 status 只能是:
适合值很稳定的场景:
注意:
ENUM 的可选值写死在表结构里。
- 如果状态经常变化,改起来不方便。
- 如果状态需要后台配置,应该单独建状态表。
例如:
CREATE TABLE enum_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
status ENUM('draft', 'published', 'archived') NOT NULL DEFAULT 'draft',
PRIMARY KEY (id)
);
七、JSON 类型
MySQL 支持 JSON 类型,适合保存结构不固定的扩展信息。
例如用户扩展资料:
插入示例:
INSERT INTO users (username, email, profile)
VALUES (
'tom',
'tom@example.com',
JSON_OBJECT('city', 'Shanghai', 'level', 3)
);
查询 JSON 字段:
SELECT
username,
JSON_EXTRACT(profile, '$.city') AS city
FROM users;
也可以使用简写:
SELECT
username,
profile->'$.city' AS city
FROM users;
JSON 适合什么
适合:
- 不固定的扩展配置。
- 第三方平台返回的原始信息。
- 临时不确定结构的补充字段。
不适合:
- 经常用于
WHERE 查询的字段。
- 经常用于排序的字段。
- 经常和其他表关联的字段。
例如用户等级经常要筛选:
那就不要长期放在 JSON 里,应该设计成普通字段:
level INT UNSIGNED NOT NULL DEFAULT 0
简单原则:
八、二进制类型
二进制类型用来保存字节数据。
常见类型:
实际项目里,不建议把图片、视频这类大文件直接塞进 MySQL。
更常见做法是:
- 文件上传到对象存储或服务器磁盘。
- MySQL 只保存文件地址、大小、类型等元数据。
例如:
avatar_url VARCHAR(500) NULL
九、完整用户表示例
下面是一张用户表的字段设计:
CREATE TABLE users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
phone VARCHAR(20) NULL,
password_hash VARCHAR(255) NOT NULL,
age TINYINT UNSIGNED NULL,
birthday DATE NULL,
status ENUM('active', 'disabled') NOT NULL DEFAULT 'active',
profile JSON NULL,
is_deleted TINYINT UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段说明:
十、完整文章表示例
下面是一张文章表的字段设计:
CREATE TABLE posts (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT UNSIGNED NOT NULL,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
summary VARCHAR(500) NULL,
status ENUM('draft', 'published', 'archived') NOT NULL DEFAULT 'draft',
view_count INT UNSIGNED NOT NULL DEFAULT 0,
like_count INT UNSIGNED NOT NULL DEFAULT 0,
published_at DATETIME NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段说明:
十一、常见错误
1. 用 INT 保存手机号
错误:
正确:
手机号不是用来计算的数字。
2. 金额使用 FLOAT
错误:
正确:
金额必须精确。
3. 年龄用 INT
不是不能用,但没必要。
更合适:
4. 主键 ID 用 INT 太保守
小项目用 INT UNSIGNED 也能跑很久。
但新项目如果不确定数据量,主键 ID 推荐直接用:
尤其是用户、订单、日志、流水这类可能增长很快的表。
5. 所有文本都用 TEXT
错误:
username TEXT
email TEXT
title TEXT
更合适:
username VARCHAR(50)
email VARCHAR(100)
title VARCHAR(200)
TEXT 留给真正可能很长的内容。
6. 可以为空和不能为空不明确
不推荐:
推荐明确写:
username VARCHAR(50) NOT NULL
或者:
建表时明确写 NULL 或 NOT NULL,后面读表结构的人更容易理解。
十二、类型选择速查表
记住一句话: