【MySQL初阶】03-常见的数据类型
前言:学习完库的操作之后,我们将来是需要再库中建立相应的数据表的,那么在建表之前,我们得需要将数据类型给掌握了,因为建表的时候每一个字段(列)都会指定对应的数据类型。
数字相关类型
数据类型 | 大小 | 说明 | 表示范围 | 对应 java 类型 |
---|---|---|---|---|
bit[(m)] | m 指定位数,默认为 1 | 二进制数,m 范围从 1 到 64,存储数值范围从 0 到 2^m -1 | 0 到 2^m - 1(m 为 1-64,默认 m=1 时范围为 0-1) | 常用 boolean 对应 bit,此时默认是 1 位,即只能存 0 和 1 |
tinyint | 1 字节 | 有符号:-128 到 127;无符号:0 到 255 | Byte | |
smallint | 2 字节 | 有符号:-32768 到 32767;无符号:0 到 65535 | Short | |
int | 4 字节 | 有符号:-2147483648 到 2147483647;无符号:0 到 4294967295 | Integer | |
bigint | 8 字节 | 有符号:-9223372036854775808 到 9223372036854775807;无符号:0 到 18446744073709551615 | Long | |
float(m,d) | 4 字节 | 单精度,m 指定长度,d 指定小数位数。会发生精度丢失 | 约 ±3.402823466e+38(单精度浮点范围) | Float |
double(m,d) | 8 字节 | 约 ±1.7976931348623157e+308(双精度浮点范围) | Double | |
decimal(m,d) | m/d 最大值 + 2 | 双精度,m 指定长度,d 表示小数位数。精确数值 | 由 m 和 d 决定,m 最大 65,d 最大 30,范围为 - 10^m 到 10^m-1(根据 d 保留小数位) | BigDecimal |
numeric(m,d) | m/d 最大值 + 2 | 和 decimal 一样 | 与 decimal (m,d) 相同 | BigDecimal |
说明:
int 和 bigint补充说明
为了避免数据上限的风险一般使用bigint来表示编号,对于普通的数据使用int,同时如果编号是中等则可用int,总之都是根据需求来的。
float、double、decimal 补充说明
float
和double
类型,在表示小数的时候都不是特别精准,所以用decimal
类型去表示小数。- 有些系统中表示金额,一般把 “元” 为单位换成 “分” 为单位,然后用
int
类型去表示金额。
DECIMAL (M,D)细节规则
- M 中不计算小数、符号(如负号);如果 D 为 0,则值不保存小数点和小数部分(即保存整数)。
- DECIMAL 的最大位数(M)为 65,支持最大的小数(D)为 30。
- 如果省略 D,默认 D 为 0;如果省略 M,默认 M 为 10。
- 只需知道:DECIMAL 可以保存很大的数,可根据项目要求设置小数精度。
字符串相关类型
数据类型 | 大小范围 | 说明 | 对应 java 类型 | 典型使用场景 |
---|---|---|---|---|
char(n) | 0–255 字节(n 为字符数) | 定长字符串,不足 n 则用空格填充,查询时自动去除尾部空格 | string | 身份证号、固定长度编码(如性别) |
varchar(n) | 0–65535 字节(n 为字符数) | 变长字符串,按实际长度存储,更节省空间 | string | 用户名、标题、短描述 |
tinytext | 0–255 字节 | 短文本数据,存储小段落内容 | string | 新闻速报、标签 |
text | 0–65535 字节(64 kb) | 长文本数据,存储中等长度内容 | string | 文章正文、备注 |
mediumtext | 0–16777215 字节(16 mb) | 中等长度文本数据,存储长文或富文本 | string | 小说章节、产品详情 |
longtext | 0–4294967295 字节(4 gb) | 极大文本数据,存储超长篇内容 | string | 学术论文、日志全文 |
tinyblob | 0–255 字节 | 二进制短数据,存储小文件或二进制片段 | byte[] | 小图标、缩略图 |
blob | 0–65535 字节(64 kb) | 二进制长数据,存储中等大小二进制内容 | byte[] | 图像、音频片段 |
mediumblob | 0–16777215 字节(16 mb) | 二进制中等长度数据,存储较大文件 | byte[] | 高清图片、短视频 |
longblob | 0–4294967295 字节(4 gb) | 二进制极大数据,存储超大文件 | byte[] | 高清视频、大型压缩包 |
说明:
我们的数据库一般不会存储二进制文件的,二进制文件很大,一般我们都是现将他直接存储在硬盘上,然后将地址存储到数据库中的,所以对于二进制的类型(如blob等)了解即可,基本用不到。
关键说明
字符 vs 字节:
char(n)
和varchar(n)
中的n
指字符数(而非字节)。例如,varchar(50)
在 utf-8 编码下可存 50 个汉字(每个汉字占 3 字节)。- 二进制类型(
blob
系列)的大小指字节数,无字符概念。
定长 vs 变长:
char
是定长存储,适合长度固定的场景(如身份证号),但可能浪费空间;varchar
是变长存储,更灵活,适合长度不确定的场景(如用户名)。
文本 vs 二进制:
text
系列存储字符数据(如文章、日志),需指定字符集;blob
系列存储二进制数据(如图片、视频),按字节存储,不涉及字符集。
性能与限制:
text
和blob
类型不能设置默认值,且查询性能略低于varchar
;- 若存储超长篇内容(如 gb 级文件),建议用
longblob
,但需注意数据库性能优化。
常见问题:
varchar(SIZE)
指定的是字符串的长度(字符数),不是字节大小。例如varchar(10)
表示字段可存 10 个及以内字符,超过则报错。
1.比如name varchar(20)是不是代表我的名字在20个字以内?
回答:是的,name varchar(20)
意味着您最多可以存储20个字符,无论是英文、数字、汉字还是一个表情符号,都算作一个字符。
下面为您详细解释清楚:
核心概念:varchar(n)
中的 n
指的是“字符数”,而不是“字节数”
“字符”是什么?
一个英文字母(如
a
、B
)是一个字符。一个数字(如
1
、9
)是一个字符。一个汉字(如
你
、我
)也是一个字符。一个Emoji表情(如
😊
)同样算一个字符。
“字节”是什么?
字节是计算机存储的基本单位。不同的编码方式下,一个字符占用的字节数可能不同。
在MySQL最常用的
utf8mb4
编码(现代默认,支持所有字符包括Emoji)下:一个英文字符占用 1个字节。
一个中文字符占用 3个字节。
一个Emoji表情占用 4个字节。
结合例子 name varchar(20)
来分析:
定义的限制:这个定义限制的是字符数量最多为20个。
实际存储:数据库会根据你实际存入的字符,动态计算需要占用多少字节。
举例说明:
您存入的名字 | 字符数 | 是否超出varchar(20) 限制? | 实际占用存储空间(字节,按utf8mb4计算) |
---|---|---|---|
zhangsan | 8个 | 否 | 8 * 1字节 = 8字节 |
张三 | 2个 | 否 | 2 * 3字节 = 6字节 |
张三丰是个大侠 | 7个 | 否 | 7 * 3字节 = 21字节 |
欧阳锋的侄子欧阳克 | 10个 | 否 | 10 * 3字节 = 30字节 |
这是一个非常非常长的名字超过了限制 | 比如25个 | 是 | 数据库会报错或截断,无法完整存入 |
结论:
只要您的名字的字符总数不超过20个,无论它是英文、中文还是混合的,都可以成功存入
varchar(20)
的字段中。数据库会自动处理底层字节的存储,您只需要关心字符个数即可。
给初学者的重要提醒(避免踩坑)
不要混淆“字符”和“字节”:建表时
varchar(255)
想的是“能存255个汉字”,这是对的,因为它指的是255个字符。最大长度限制是“行限制”:虽然
varchar
理论上最大能支持到65535字节,但这受限于MySQL单行所有字段的总长度不能超过65535字节。所以您不可能定义一个varchar(20000)
来存一万个汉字。最佳实践:根据实际情况合理设置长度。比如:
username varchar(50)
email varchar(100)
nickname varchar(20)
不要所有字符串字段都盲目地用
varchar(255)
,这是一种浪费,并且可能影响性能(例如,作为索引时)。
2.数据库中建不建议直接存文件?
- 数据库中不建议直接存文件,而是把文件存在磁盘上,数据库字段保存文件路径。
- 查询文件时:先从数据库取文件路径,再根据路径到磁盘加载 / 返回真实文件。
3.文本文件 vs 二进制文件
- 文本文件:人类可直接看懂,如记事本日记、配置文件、Java 源代码。
- 二进制文件:文本编辑器打开是乱码,只有机器能读懂。
时间日期相关
类型 | 格式 | 范围 | 时区 | 存储空间 | 特点 |
---|---|---|---|---|---|
date | yyyy-mm-dd | 1000-01-01 ~ 9999-12-31 | 无 | 3字节 | 只存储日期 |
time | hh:mm:ss | -838:59:59 ~ 838:59:59 | 无 | 3字节 | 只存储时间 |
datetime | yyyy-mm-dd hh:mm:ss | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 无 | 8字节 | 存日期和时间(最常用) |
timestamp | 时间戳 | 1970-01-01 00:00:01 ~ 2038-01-19 03:14:07 | 自动转换 | 4字节 | 自动时区转换 |
说明:
最常用的就是datatime其他的了解即可
为什么datetime最常用
datetime的优势:
范围更大:避免2038年问题(timestamp在2038年过期)
直观易读:存储什么值就是什么值,没有时区转换
兼容性好:与java的
localdatetime
直接对应
java对应关系:
datetime →
java.time.localdatetime
date →
java.time.localdate
time →
java.time.localtime
最常用数据类型总结
数值类型
1. tinyint - 小整数专家
使用场景:
状态标志:
status tinyint default 1
(0-禁用,1-启用)性别标识:
gender tinyint
(0-未知,1-男,2-女)年龄范围:
age tinyint unsigned
(0-255岁足够)类型枚举:
user_type tinyint
(普通用户、vip、管理员等)
注意事项:
✅ 一定要用
unsigned
当数值不会为负时✅ 对于真假值,用
tinyint(1)
更语义化❌ 不要用它存储可能超过255的数字
2. int - 通用整数之王
使用场景:
普通计数:
view_count int unsigned default 0
排序字段:
sort_order int default 0
外键关联:
user_id int unsigned
中等范围id:
category_id int unsigned
注意事项:
✅ 无符号时范围0-42亿,能满足大部分业务
❌ 不要用作海量数据表的主键(有上限风险)
⚠️
int(11)
中的11只是显示宽度,不影响存储
3. bigint - 海量数据卫士
使用场景:
主键id:
id bigint unsigned auto_increment primary key
分布式id:
snowflake_id bigint
金融交易号:
transaction_id bigint unsigned
大数据统计:
total_amount bigint
注意事项:
✅ 新建项目主键一律推荐使用bigint
✅ 范围极大,彻底避免数据溢出问题
❌ 存储小数字时比int多耗一倍空间,不划算
4. decimal(m,d) - 精确计算专家
使用场景:
金融金额:
price decimal(10,2)
(总10位,小数2位)利率计算:
interest_rate decimal(5,4)
科学计量:
weight decimal(8,3)
百分比:
discount decimal(3,2)
注意事项:
✅ 金额计算必须用decimal,避免浮点误差
✅ m表示总位数,d表示小数位数
⚠️ 计算性能比float/double稍慢,但保证精确
❌ 不要用float/double存储金额!
字符类型
1. varchar(m) - 灵活字符串首选
使用场景:
用户信息:
username varchar(50)
,email varchar(100)
标题描述:
title varchar(200)
,description varchar(500)
地址信息:
address varchar(255)
编码标识:
code varchar(20)
注意事项:
✅ m指字符数,不是字节数(可以存m个汉字)
✅ 合理预估最大长度,避免过度分配
❌ 不要所有字段都用
varchar(255)
⚠️ 最大长度受行限制约(约65535字节)
2. text - 大文本内容专家
使用场景:
文章内容:
content text
产品详情:
details text
日志信息:
log_message text
富文本存储:
html_content text
注意事项:
✅ 无需指定长度,自动适应内容大小
❌ 性能较差,避免在where条件中频繁使用
❌ 不能有默认值
⚠️ 考虑是否需要更大的
mediumtext
或longtext
日期类型
1. date - 纯日期专家
使用场景:
生日:
birthday date
纪念日:
anniversary date
有效期:
expiry_date date
统计日期:
stat_date date
注意事项:
✅ 只关心日期不关心时间时使用
✅ 存储空间小(3字节),查询性能好
❌ 不能存储时间信息
2. datetime - 完整时间戳标准
使用场景:
创建时间:
created_time datetime default current_timestamp
更新时间:
updated_time datetime on update current_timestamp
订单时间:
order_time datetime
计划时间:
scheduled_time datetime
注意事项:
✅ 范围大(1000-9999年),无2038年问题
✅ 无视区转换,存储什么值就是什么值
✅ 对应java的
localdatetime
❌ 比timestamp占用更多空间(8字节 vs 4字节)
核心原则总结
主键安全:用
bigint
避免上限问题金额精确:用
decimal
避免计算误差字符串灵活:用
varchar
按需分配时间可靠:用
datetime
避免时区困扰空间经济:小数据用小程序(如
tinyint
代替int
)
提问:现在是不是编号一般使用bigint;对于普通数字使用int;对于字符串使用的是varchar ;对于小数使用的是deciaml; 对于时间日期一般使用datatime?
数据种类 | 首选类型 | 原因分析 |
---|---|---|
编号/主键ID | BIGINT | ✅ 正确。避免INT 的21亿条数据上限,为系统长远发展留足空间。自增主键:id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY |
普通数字 | INT | ✅ 正确。对于年龄、数量、状态码等不会很大的数字,INT 范围足够且更节省空间。 |
字符串/文本 | VARCHAR | ✅ 正确。绝大多数字符串场景都适用,灵活节省空间。需合理指定长度,如VARCHAR(100) 。 |
小数/金额 | DECIMAL | ✅ 正确。保证绝对精度,无浮点数误差,是金融、交易等场景的唯一选择。 |
时间日期 | DATETIME | ✅ 正确。范围大(1000-9999年),无视区问题,直观易用,是目前的事实标准。 |
深入探讨与细微注意事项
1. 编号为什么倾向用 bigint而不是 int
?
核心原因:避免“数据上限”风险。
INT
无符号最大约42亿条,对于成长性好的互联网应用,这个上限可能在未来被触及。最佳实践:新建项目,尤其是可能产生海量数据的项目,主键ID一律使用
bigint
。空间代价(8字节 vs 4字节)在当今硬件下可以忽略不计,但换来的是长远的安全感。
2. 字符串为什么是 varchar
而不是 char
?
核心原因:空间利用率。varchar按需分配空间,而 char会固定占用定义的长度。
例外情况:如果存储的内容长度完全固定,比如MD5哈希值(32位)、UUID(36位)、国家代码(2位),使用 char性能会稍好一些,因为存储结构更简单。
结论:不确定长度的字符串,无脑用
VARCHAR
。
3. 时间日期为什么是 datetime而不是 timestamp
?
核心原因:
timestamp
的“2038年问题” 和 时区自动转换的不可控性。timestamp
的遗留用途:在一些特定场景仍有用武之地:需要记录数据行的自动更新时间(
updated_time timestamp default current_timestamp on update current_timestamp
)。需要数据库层面做跨时区自动转换的国际化应用。
结论:记录具体的业务时间(如订单时间、用户生日),一律用
datetime
。