
你CREATE DATABASE建完数据库转头就INSERT用户数据会吃一记报错ERROR 1046 (3D000): No database selected。因为数据库一行数据都不存它只是个“文件夹”。这篇带你从零建一张user_info用户表库、表、字段、记录、主键五个概念顺着一条线全串明白每一步都能自己跑、自己验。文章目录一、数据到底存在哪儿数据库Database只是个“文件夹”二、谁真正装数据数据表Table三、空表的“形状”由谁定字段列Column四、人怎么“进表”记录行Row五、两行数据“撞号”了怎么办主键Primary Key六、回头串一遍用户数据是怎么被安放好的写在最后一、数据到底存在哪儿数据库Database只是个“文件夹”很多新手以为数据是“放进数据库里”的。不是。MySQL 的存储是一层套一层的结构MySQL 服务实例 → 数据库 → 数据表 → 字段/列、记录/行 → 主键。最外层的 MySQL 服务实例就是你装好 MySQL 后启动的那个服务进程库是它下面隔出来的房间。库里也不只有表视图、索引、存储过程这些对象都归库管但业务数据只落在表里。我习惯用写字楼打比方一次就能记牢MySQL 服务是一栋写字楼数据库Database是楼里的独立办公室一间办公室放一类业务数据数据表是办公室里的档案柜一个柜子对应一类具体数据字段是每份档案上的固定栏目姓名、年龄、手机号记录是一张填好的档案单据主键是单据上的唯一编号保证不重复、能精准定位。实际项目里就一条规矩一项目一数据库。用户表、订单表、商品表、评论表同一个项目的表全放一个库里商城用shop_db、博客用blog_db两个库互相独立、权限能单独配数据不会串。反过来一个库里混着好几个项目的表备份时不知道该带谁、权限没法按项目分迟早出事故。库名也按项目起user_system_db一看就是用户系统的库。为什么要拆库三个好处都是踩出来的各库相互独立、数据互不干扰权限还能单独配——你可以让 A 项目的账号只碰得到shop_db连blog_db的门都摸不到同一个业务的表、索引、触发器归在一个库里备份、迁移都按项目整体走不用一张张表操心。库还能单独指定字符集和排序规则字符集决定能存什么字排序规则决定字怎么比、怎么排。中文乱码、排序异常都在这一层解决。来亲手把“办公室”盖出来命令适配 MySQL 8.0SHOWDATABASES;CREATEDATABASEIFNOTEXISTSuser_system_dbDEFAULTCHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;USEuser_system_db;SELECTDATABASE();✅验证最后一条返回user_system_db说明你已经“走进这间办公室”后面的操作才会落在这个库里不USE就插数据就是开头的 1046 报错。这里指定utf8mb4一个字符最多 4 字节所有中文、表情符号都存得下。⚠️坑DROP DATABASE会连库带表带数据一起清空且不可回滚。练手库随便删生产库碰都别碰。记住数据库是“办公室”只做隔离和归类本身不存一行业务数据。办公室有了可数据总不能摊在地上——得往屋里摆档案柜。柜子就是数据表。二、谁真正装数据数据表Table数据表Table才是真正存储业务数据的基本单元。库只管表用户信息、订单信息、商品信息全存在表里。表是一张二维的行列表格结构规整、好查好管。一个库里可以放几十上百张表每张表负责一个维度的数据。而且你往后写的绝大多数 SQL——增、删、改、查——操作对象都是表。库是后勤表才是前线。设计上遵循单一职责一张表只存一类核心业务数据。我们要建的user_info只存注册用户的基础信息——账号、密码、昵称、手机号、注册时间、状态订单、权限这些维度另开表。表混着用字段越堆越多查询、维护一起受罪。先把柜子打出来CREATETABLEIFNOTEXISTSuser_info(idINTCOMMENT用户唯一ID主键,usernameVARCHAR(30)NOTNULLCOMMENT用户登录账号,passwordVARCHAR(64)NOTNULLCOMMENT用户登录密码,nicknameVARCHAR(20)DEFAULTCOMMENT用户昵称,phoneCHAR(11)DEFAULTCOMMENT用户手机号,create_timeDATETIMEDEFAULTCURRENT_TIMESTAMPCOMMENT注册时间,statusTINYINTDEFAULT1COMMENT账号状态1正常 0禁用)ENGINEInnoDBDEFAULTCHARSETutf8mb4COMMENT用户信息基础表;注意看第一行id的注释写着“主键”但这张表其实没有主键——我故意的先卖个关子。要点注释只是给人看的文字PRIMARY KEY约束才真正生效。现在执行SELECT * FROM user_info;只回你Empty set柜子和栏目都有了里面一张单据都没有。记住表才是真正装数据的柜子一张表只管一类业务。柜子有了那“姓名栏、手机号栏”这些格子是怎么定下来的三、空表的“形状”由谁定字段列Column表的栏目就是字段也叫列Column。它是表中纵向的属性维度说白了就是表头——规定这张表能存哪些维度、每个维度什么格式。每个字段有五样东西字段名、数据类型、约束条件、默认值、注释。字段名在一张表里不能重就像一张档案上不能印两个“姓名”栏数据类型和约束则把每栏能填什么焊死。对照刚建的表字段类型约束 / 默认含义idINT—用户唯一 IDusernameVARCHAR(30)NOT NULL登录账号passwordVARCHAR(64)NOT NULL登录密码nicknameVARCHAR(20)DEFAULT ‘’用户昵称phoneCHAR(11)DEFAULT ‘’手机号create_timeDATETIMEDEFAULT CURRENT_TIMESTAMP注册时间statusTINYINTDEFAULT 11 正常 / 0 禁用顺带看两个细节每个字段都带COMMENT注释表尾还有COMMENT用户信息基础表——日后翻到这张表一眼知道它存什么。类型不是随便挑的我说下我的判断手机号固定 11 位用CHAR(11)定长不浪费、比较快账号、昵称长短不一用VARCHAR按实际长度占空间注册时间用DATETIME默认值CURRENT_TIMESTAMP插入时不用手填状态只有 0 和 1TINYINT就够没必要用大类型NOT NULL表示这栏必须给值DEFAULT表示没给就自动填默认值。归纳一下字段设计就三条必要性只留业务必需的字段冗余字段一个都别加白白占存储还容易写错精准性数据类型选得准定长用 CHAR、变长用 VARCHAR、时间用 DATETIME前面已经对照过规范性名字统一小写加下划线、见名知意禁止中文和特殊符号注释一定写——后人接手不骂人这是团队协作的基本功。要点字段定的是规则——能存什么、什么格式、能不能空建表那一刻就锁死了。记住字段是表的“栏目”和规则纵向固定决定一张表长什么样。栏目印好了张三这个大活人怎么才能变成表里的一行四、人怎么“进表”记录行Row填进栏目里的真实内容叫记录也叫行Row。字段是规则框架记录就是按框架填好的真实数据——一行对应一个完整用户。把张三、李四请进表INSERTINTOuser_info(id,username,password,nickname,phone,status)VALUES(1,zhangsan,123456,张三,13800138000,1),(2,lisi,654321,李四,13900139000,1);SELECT*FROMuser_info;id1 zhangsan 张三 13800138000 status1 id2 lisi 李四 13900139000 status1 create_time 由 DEFAULT CURRENT_TIMESTAMP 自动填入不用手写注意我们没传create_time查出来它已经有值了——默认值就是干这个的你不给数据库替你填。字段和记录谁也离不开谁没有字段表没有框架数据不知道往哪填没有记录表就是个空框架没有任何业务价值。字段定维度和规则记录填内容和实例。现在再看这张表关系就清楚了纵向是字段列固定不变是结构横向是记录行可以随时新增、修改、删除是数据。一张表能放无数条记录但每条都得遵守同一套字段规则。用户改昵称就 UPDATE 对应那一行用户注销就 DELETE 那一行——动的永远是行表头始终不动。记住一条记录就是字段规则下的一行真实数据一行对应一个用户。现在两个用户的 id 是 1 和 2。要是我手滑再插一条id1的会怎样按直觉该报错吧五、两行数据“撞号”了怎么办主键Primary Key别猜动手试INSERTINTOuser_info(id,username,password)VALUES(1,fake_zhangsan,123456);SELECTid,usernameFROMuser_infoWHEREid1;------------------- | id | username | ------------------- | 1 | zhangsan | | 1 | fake_zhangsan | ------------------- 2 rows in set看到了吧没有主键数据库根本不拦你。一个 id1 查出两个人谁是真张三数据从这一刻起再也分不清后面的关联查询、按 id 定位全乱。⚠️坑字段叫id、注释写“主键”都不顶用。没有PRIMARY KEY约束重复值就能大摇大摆混进表。解决它靠主键约束Primary Key简称 PK——它是唯一标识每一行的特殊字段相当于每条数据的身份证。四个特性记牢唯一id 值绝不重复id1 只对应张三非空主键不能为 NULL每条数据都必须有 id想插一条没 id 的记录直接被拒稳定id 一旦生成别乱改它永久对应这条数据订单表等其他表可能正用这个 id 做关联一改关联就断自带索引主键会自动创建主键索引按 id 查询是表里最快的。一张表有且只有一个主键。把旧表删掉、重建这次带上主键和自增DROPTABLEIFEXISTSuser_info;CREATETABLEIFNOTEXISTSuser_info(idINTPRIMARYKEYAUTO_INCREMENTCOMMENT用户唯一ID主键自增,usernameVARCHAR(30)NOTNULLCOMMENT用户登录账号,passwordVARCHAR(64)NOTNULLCOMMENT用户登录密码,nicknameVARCHAR(20)DEFAULTCOMMENT用户昵称,phoneCHAR(11)DEFAULTCOMMENT用户手机号,create_timeDATETIMEDEFAULTCURRENT_TIMESTAMPCOMMENT注册时间,statusTINYINTDEFAULT1COMMENT账号状态1正常 0禁用)ENGINEInnoDBDEFAULTCHARSETutf8mb4COMMENT用户信息基础表;自增属性AUTO_INCREMENT新插入一行id 自动 1不用手填从根上杜绝重复和遗漏。手动发号是什么下场两个人同时注册都查到当前最大 id 是 5于是都插 id6——又撞了。自增由数据库统一发号天然没这个问题。主键分两种。单字段主键由一个字段构成是最标准的用法通常用INT数据量特别大的场景用BIGINT搭配AUTO_INCREMENT新增数据自动发号简洁高效、适配性极强实际开发里 99% 的场景用的都是它。复合主键由两个及以上字段组合成唯一主键只用在特殊的关联表场景普通业务表几乎不会出现新手不用重点掌握。重建会清空数据把张三、李四的 INSERT 再跑一遍这次不用写 id然后验证INSERTINTOuser_info(username,password)VALUES(wangwu,123456);INSERTINTOuser_info(id,username,password)VALUES(1,dup,123456);第一行成功id 自动取 3 第二行失败ERROR 1062 (23000): Duplicate entry 1 for key user_info.PRIMARY✅验证重复 id 在写入环节就被拒之门外这就是主键“从根源避免数据重复”的含义。再把数据查出来看张三、李四的 id 还是 1、2wangwu 是 3号段连续、不重号。❌错误手动给主键赋值。重复、遗漏都难免让AUTO_INCREMENT自己发号或者用雪花算法别手填。记住主键是每行数据的身份证唯一、非空、还自带最快的索引自增主键别手填。六、回头串一遍用户数据是怎么被安放好的从盖办公室到发身份证一条线走完。对着案例再看一遍层级层级写字楼类比user 案例一句话职责数据库办公室user_system_db隔离、归类一整个项目的数据数据表档案柜user_info真正存数据一表一类业务字段列档案栏目id、username、phone定属性、类型和约束记录行档案单据张三那一行一个用户的完整数据主键单据唯一编号id自增唯一标识精准定位想确认主键真的生效可以让 MySQL 把建表语句吐出来给你看查看表结构确认主键生效SHOW CREATE TABLE user_info;结果里找得到PRIMARY KEY(id) 和AUTO_INCREMENT就说明主键和自增都就位了。这套规矩不分项目大小个人博客也好大厂的分布式系统也好数据都按这套层级安放。记住从库到主键是“容器 → 柜子 → 栏目 → 单据 → 编号”的嵌套少了哪一层数据都安放不稳。写在最后总结数据库管隔离数据表管存储字段定规则记录填内容主键保唯一——五个概念不是五个并列考点是安放一条用户数据的五个环节。术语速查表中文English一句话数据库Database数据容器一项目一库数据表Table真正存数据的二维表格字段列Column纵向表头定属性和规则记录行Row横向一行一条业务数据主键约束Primary KeyPK唯一、非空一表一个自增AUTO_INCREMENT主键自动发号字符集utf8mb4中文、表情都能存新手高频坑清单库和表搞混库不存数据表才存不USE就操作 → 1046字段和记录搞混纵向固定的是列横向动态的是行表不设主键重复数据混进来查不准、联不上、还慢手填主键重复、遗漏难免交给AUTO_INCREMENT字符集偷懒不用utf8mb4中文乱码、表情存不进。下一步行动现在打开一个客户端按顺序跑一遍——建库 →USE→ 建带主键的表 → 插两个用户不写 id→ 故意插一条重复 id亲眼看着 1062 报错把它拦下。参考链接MySQL 8.0 Reference Manual - CREATE DATABASE StatementMySQL 8.0 Reference Manual - CREATE TABLE StatementMySQL 8.0 Reference Manual - AUTO_INCREMENT Handling in InnoDBMySQL 8.0 Reference Manual - The utf8mb4 Character Set