尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MySQL库操作全解析:从建库到删库的实战避坑指南

MySQL库操作全解析:从建库到删库的实战避坑指南 很多人学MySQL上来就奔着建表、写查询、搞索引去了结果没过多久就被各种稀奇古怪的问题卡住明明语句没问题程序却报错找不到数据库本地跑得好好的部署到服务器上一堆乱码一个不留神把整个库删了找不回来。这些坑十有八九都出在“库的操作”这个最基础的环节上。这篇文章就专门聊聊MySQL里“库”这一层的操作。不聊高深的调优不聊复杂的架构就踏踏实实把数据库的创建、查看、修改、删除、字符集设置、权限边界这些基本功捋一遍再附上我在实际运维和开发过程中踩过的坑。学完这一篇你再往下去碰表、索引、事务那些东西心里会踏实很多。1. 先从宏观上理解“库”到底是什么1.1 数据库在MySQL里扮演的角色你可以把MySQL想象成一栋大型写字楼数据库Database就是楼里的一个个独立办公室。办公室之间有隔断互相不干扰但共用大楼的水电网络。在这个比喻里表是办公室里的文件柜行和列是文件柜里的抽屉和标签而数据库就是承载这一切的物理边界。初学阶段很多人意识不到“库”这个层级的存在感。总觉得自己写的是SQL跟库有什么关系实际上MySQL几乎所有操作都是挂在某个数据库之下的。你连数据库都没选对SELECT语句写得再漂亮也白搭。更关键的是库和库之间是隔离的——同一个MySQL实例里A库和B库可以各自有相同名字的表互不冲突。这个隔离特性在生产环境里非常重要比如你同时维护订单系统和会员系统就可以拆成两个独立的库权限、备份、恢复都能分开管理。1.2 为什么必须先掌握库的操作从学习路径上看库的操作是整个MySQL体系的入口。你可以不会写复杂的JOIN但不能不会建库、删库、切库。原因有三点。第一任何业务系统落地的前提都是先有一个库建库不规范后面全白忙活。比如字符集没选对等表建好、数据写进去了再想改那真是一场灾难。第二库的操作涉及MySQL的权限体系。实际工作中你几乎不可能用root账号去操作生产库DBA会给每个业务方分配独立的账号和库权限。如果你连“GRANT SELECT ON 库名.* TO 用户”这种语句都看不懂连库都连不进去。第三库的操作是理解MySQL存储引擎、表空间、数据目录这些底层概念的钥匙。举个例子你在Linux上执行ls /var/lib/mysql会发现每个数据库对应一个目录目录里才是表结构文件和索引文件。这个认知在以后做备份、迁移、数据恢复时非常有用。2. 动手之前先把环境准备好2.1 快速确认MySQL已经安装并启动聊库操作之前先确认你手里的MySQL是能用的。我见过不少新手买了一本书看着命令行就开始敲结果第一条mysql -u root -p就报错卡在那里怀疑人生。最简单的方式是先看服务状态。Windows下打开服务管理器找“MySQL”开头的服务确认状态是“正在运行”Linux下执行systemctl status mysqld或者service mysql status看到active (running)就没问题。如果服务没起来Windows下可以右键启动Linux下执行systemctl start mysqld不同发行版服务名可能略有差异也可能是mysql。服务没问题之后再用命令行登录验证一下mysql -u root -p输入密码后能出现mysql提示符说明你已经成功进入了MySQL命令行客户端。这里有个小常识命令行客户端和MySQL服务端是两个不同的程序我们用客户端去连接服务端然后通过它来执行SQL语句。注意如果你在Linux下遇到“ERROR 2002 (HY000): Cant connect to local MySQL server through socket”这个错误基本就是服务没启动或者socket文件路径配置不对不用慌先回去检查服务状态。2.2 几个最常用的客户端工具除了原生的命令行实际工作中大家通常还会搭配图形化工具提高效率。命令行适合写脚本、做自动化运维图形化工具适合查看数据、排查问题、做开发调试。我常用的组合是命令行 Navicat或者DBeaver。Navicat是老牌工具功能很全适合Windows用户但它是收费软件网上很多“特殊版本”我不建议碰有版权风险系统不稳定还容易弄坏配置文件。DBeaver是开源免费的跨平台功能一点不弱社区版足够日常使用。图形化工具的连接配置很简单主机填localhost或127.0.0.1端口默认3306用户名和密码就是你命令行登录时用的那套。连不上时优先检查服务是否启动、端口是否被占用、用户是否有远程登录权限这个问题后面专门讲。2.3 查看当前MySQL版本和基本信息登录进去之后第一件事先搞清楚你手里的版本。不同版本的SQL语法细节略有差异特别是MySQL 8.0和5.7之间的字符集默认值、认证插件、窗口函数支持度都有区别。SELECT VERSION();还可以顺手看看当前连接的用户是谁、当前选中的库是哪个SELECT CURRENT_USER(); SELECT DATABASE();SELECT DATABASE()这个函数很实用。有时候你连接上数据库后忘记自己选的是哪个库一执行SELECT就报“Table doesnt exist”多半就是库选错了。命令行里可以执行USE 库名;来切换图形化工具双击库名也能切换。3. 库操作的五个核心命令3.1 创建数据库最简单的语句最深的坑创建数据库的语法非常简单标准写法是CREATE DATABASE [IF NOT EXISTS] 库名;比如创建一个名为school的数据库CREATE DATABASE IF NOT EXISTS school;IF NOT EXISTS这个可选项是做什么用的字面意思是“如果不存在才创建”加上它之后即使库已经存在也不会报错只是给一个警告。不加它重复创建就会报ERROR 1007 (HY000): Cant create database school; database exists。但新手往往栽在库名的规范上。MySQL的库名在Windows下不区分大小写在Linux下区分大小写为了避免迁移时的各种诡异问题统一建议库名全部用小写字母、数字、下划线不要用大写不要用中文不要用特殊字符。比如user_db可以UserDB不推荐用户库更不要考虑后患无穷。还要说一个很容易被忽视的问题库名不要跟MySQL的系统库重名。information_schema、mysql、performance_schema、sys这4个库是系统自带的你自建库千万别起这些名字否则可能导致系统表数据异常轻则功能奇怪重则实例起不来。3.2 查看数据库列表学会用LIKE做筛选创建好之后怎么知道创建成功了执行SHOW DATABASES;这个命令会列出当前MySQL实例里所有的数据库。你会看到系统自带的几个库再加上你自己创建的school。当库特别多的时候SHOW DATABASES刷屏刷到怀疑人生可以用LIKE来过滤SHOW DATABASES LIKE s%;这条语句会列出所有以s开头的数据库。LIKE后面的%是通配符表示任意长度的任意字符。如果只想查school这一个库是否精确存在可以写SHOW DATABASES LIKE school;。想查看某个库的详细信息比如字符集、排序规则、目录名可以用SHOW CREATE DATABASE school;这个命令会返回建库时的完整语句非常直观也是我推荐新手多看的一个命令。它能帮你看清楚一个库到底用了什么字符集、什么排序规则后面排查乱码问题时特别有用。3.3 切换到指定数据库USE之前的灵魂拷问MySQL里切换数据库的语法是USE 库名;比如USE school;之后你执行的所有表操作都会在这个库下进行。需要留意的是USE是MySQL客户端特有的指令不是标准SQL但它太常用了几乎所有开发者都会用到。图形化工具里双击库名也能实现同样效果。切换库这个动作看似不起眼实操中经常埋雷。比如你在school库里建了表第二天打开客户端没执行USE school直接写SELECT * FROM student;会立刻报ERROR 1046 (3D000): No database selected。解决方式有两个要么先执行USE school要么在表名前面加上库名前缀写成SELECT * FROM school.student;。这个“库名.表名”的写法叫做全限定表名在任何情况下都不会产生歧义。我建议你在写跨库查询、存储过程、定时任务里的SQL时都尽量用全限定写法减少出错概率。3.4 修改数据库参数字符集和排序规则的调整生产环境中建库之后修改配置的情况很少但也不是完全没有。比如前期规划不周库的默认字符集建错了但表还没建几个这时改库的默认字符集是成本最低的补救方式。修改数据库的语法是ALTER DATABASE 库名 [DEFAULT] CHARACTER SET 字符集名 [DEFAULT] COLLATE 排序规则名;比如把school库改成utf8mb4字符集、utf8mb4_general_ci排序规则ALTER DATABASE school DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;这里要特别注意这个操作只改变库的“默认设置”不会自动修改库里已经存在的表的字符集更不会修改已存数据的编码。也就是说如果表已经用latin1建好了数据也是latin1存的你改了库的默认字符集并不会让历史表跟着变。想要彻底改得逐表执行ALTER TABLE 表名 CONVERT TO CHARACTER SET utf8mb4;但这些就属于表操作的范畴了这里不展开。你只需要记住一个结论字符集这种坑最好在建库时就选好后期修改代价很大。3.5 删除数据库一个回车就是一辈子删除数据库的语法DROP DATABASE [IF EXISTS] 库名;比如DROP DATABASE IF EXISTS school;加了IF EXISTS之后库不存在时不会报错只给警告。不加的话库不存在会报ERROR 1008 (HY000): Cant drop database school; database doesnt exist。关于删除操作我必须多说两句。DROP DATABASE会连同库里的所有表、所有数据全部删除而且这个操作通常不可恢复。MySQL官方文档也没有提供撤销DROP DATABASE的机制。你在生产环境执行这条语句之前扪心自问三遍备份了吗备份了吗备份了吗我自己的经验是生产环境的标准做法是“先备份再删除最后验证”。也就是先用mysqldump把库完整导出一份到本地文件确认备份文件能正常打开、能看到关键表的数据然后再执行DROP DATABASE。删除后还要再登录查一次SHOW DATABASES确认库确实没了才算完成。4. 字符集与排序规则库操作里最容易被忽视的细节4.1 什么是字符集为什么utf8mb4是首选字符集决定了一个数据库用什么编码存文本。常见的字符集有utf8mb4、utf8、latin1、gbk等。MySQL里的utf8其实是一个坑它最多用3个字节存储一个字符装不下emoji和一些特殊汉字真正完整的UTF-8编码是utf8mb4mb4即“most bytes 4”最多4字节。我建议所有新库一律用utf8mb4。原因很简单第一它能存全量Unicode字符包括emoji第二它是当前互联网应用的事实标准兼容性最好第三MySQL 8.0的默认字符集就是utf8mb4官方已经替你选好了正确答案。创建数据库时指定字符集的完整写法CREATE DATABASE IF NOT EXISTS school DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;如果你不指定MySQL会按照配置文件里的默认值来。MySQL 5.7的默认字符集还是latin1这就是很多人建完库发现中文乱码的根本原因MySQL 8.0默认就是utf8mb4所以如果你用的是8.0这步可以省心不少。但为了稳妥和可读性我建议建库脚本里始终显式写清楚字符集和排序规则不要把命运交给默认值。4.2 排序规则的选择ci和bin的区别排序规则是字符集的配套属性决定字符串比较时“是否区分大小写”“是否区分重音”等规则。常用的有排序规则说明适用场景utf8mb4_general_ci不区分大小写比较速度快大多数业务系统utf8mb4_unicode_ci不区分大小写排序规则更标准多语言、国际化应用utf8mb4_bin区分大小写按二进制比较对大小写敏感的业务比如用户名登录这里有一个真实案例。有个朋友做账号系统建库时用了utf8mb4_general_ci导致注册账号时“Admin”和“admin”被当成同一个用户名数据库唯一索引直接拦截了第二个注册请求。排查了半天才找到原因最后把用户表的排序规则改成utf8mb4_bin才解决。这提醒我们建库时多花一分钟想清楚排序规则以后能省一天排查问题的时间。MySQL 8.0的默认排序规则是utf8mb4_0900_ai_ci它是基于Unicode 9.0标准的新排序规则比老的utf8mb4_general_ci更准确对重音符号的处理也更合理。如果你没有特殊诉求直接用默认值即可。4.3 客户端连接字符集一个经常引发乱码的环节即使库和表的字符集都正确你还有可能遇到乱码原因是客户端连接时的字符集不对。MySQL连接建立后客户端往服务端发送的SQL语句、服务端返回的结果集都需要通过“连接字符集”编码来解码。登录后可以执行SHOW VARIABLES LIKE character_set_client; SHOW VARIABLES LIKE character_set_results;这两个变量分别表示客户端发送SQL时使用的字符集以及服务端返回结果时使用的字符集。如果它们是latin1而你敲入的是中文SQL、期望返回中文结果那乱码就是必然的。一条命令可以统一设置三者的字符集SET NAMES utf8mb4;SET NAMES utf8mb4实际等价于同时设置character_set_client、character_set_connection和character_set_results三个变量为utf8mb4。这也是为什么我推荐在图形化工具连接时把连接字符集显式设置为utf8mb4并且在写数据库连接池配置时JDBC连接串后面务必加上characterEncodingutf8mb4Java或charsetutf8mb4其他语言从源头杜绝乱码。5. 库的权限管理和远程连接5.1 为什么要单独建用户而不是一直用root很多人练习阶段图省事一直在用root操作。练习没问题但一旦涉及多人协作或生产环境这样做非常危险。root拥有所有数据库的所有权限一旦操作失误比如DROP DATABASE写错了库名后果就是毁灭性的而且无法追溯是谁执行的。正确的姿势是每个业务系统分配一个专用账号只给这个账号需要的库的最小权限。比如school库可以创建一个school_app用户只允许它操作school.*不允许碰其他库CREATE USER school_applocalhost IDENTIFIED BY 你的强密码; GRANT SELECT, INSERT, UPDATE, DELETE ON school.* TO school_applocalhost; FLUSH PRIVILEGES;这条语句解释一下school_applocalhost表示用户只允许从本机连接school.*表示权限范围限定在school库下的所有表后面的SELECT, INSERT, UPDATE, DELETE是允许执行的操作类型。FLUSH PRIVILEGES用于刷新权限表让新授权立即生效。5.2 授权远程访问一个参数引发的连接失败如果你是开发环境需要从自己的电脑连接服务器的MySQL那就要给用户配置远程访问权限。常见做法是把用户地址从localhost改成%CREATE USER school_app% IDENTIFIED BY 你的强密码; GRANT SELECT, INSERT, UPDATE, DELETE ON school.* TO school_app%; FLUSH PRIVILEGES;%表示任何IP地址都可以连接。这样配置后就能用Navicat、DBeaver从你的电脑远程连接了。但远程连接失败时除了权限问题还要检查两件事第一bind-address配置。MySQL默认监听127.0.0.1也就是只有本机能连如果你没修改/etc/mysql/mysql.conf.d/mysqld.cnf或my.cnf里的bind-address 0.0.0.0即使授权了%也连不上。第二服务器防火墙是否放行了3306端口。很多Linux服务器默认防火墙规则很严格你需要执行firewall-cmd --add-port3306/tcp --permanent firewall-cmd --reloadCentOS或ufw allow 3306Ubuntu来放行。5.3 查看所有数据库和权限边界时的小技巧作为数据库管理员你有时需要快速了解当前实例里有哪些用户、这些用户都有什么权限。可以用以下命令SELECT User, Host FROM mysql.user;然后再针对具体用户查看权限详情SHOW GRANTS FOR school_applocalhost;这两个命令在排查“为什么这个账号能建表、那个账号不能建表”等权限类问题时非常高效。我见过太多人一遇到权限问题就去找DBA重置密码其实先自己查一下SHOW GRANTS八成就能定位到原因。6. 库操作中的常见问题与排查故障6.1 记不清密码、连不上MySQL怎么办练习阶段最尴尬的事情之一是密码忘了。如果你有系统管理员权限可以用跳过授权表的方式重置MySQL的root密码。方法大致是先停止MySQL服务然后以mysqld_safe --skip-grant-tables模式启动服务再执行mysql -u root此时不需要密码就能进去然后修改密码。这个操作的具体步骤不同系统略有差异网上教程很多。但有一点我必须强调skip-grant-tables模式意味着MySQL完全放弃权限验证任何人连上都能随意操作绝对不能在生产环境这么做也不要在开放网络环境搭建的服务器上这么做。用完立即恢复原样重启服务。6.2 乱码问题的定位和解决思路乱码问题的常见场景分两种。一种是服务端数据本身没乱码只是客户端显示乱码这种问题通常用SET NAMES utf8mb4;就能解决另一种是服务端存储的字节本身就已经错了那就要通过备份恢复的方式处理本质上是预防不到位。教你一个简单定位方法执行SELECT * FROM 表名;看结果如果乱码是问号加方框通常是存储时就错了如果只是显示时不对调整连接字符集就能看到正确中文。数据恢复是另一个复杂话题但核心教训就是建库时选对字符集连接时设置SET NAMES utf8mb4应用层连接串里显式指定编码规范操作能从源头消灭绝大多数乱码问题。6.3 库文件损坏、误删恢复的经验分享说实话数据库损坏和误删这两个场景再厉害的高手也只能事后补救真正重要的是事前防御。举一个我经历过的例子有一次在测试服务器上写自动化脚本脚本里有一句DROP DATABASE带了一个变量结果变量传错了值整个备份库被删了。好在当时有一个小时前的mysqldump备份文件恢复数据只花了十几分钟但那一瞬间的冷汗我现在还记得。因此我养成了一个习惯任何涉及DROP或ALTER的SQL写完之后先不要急着执行。先EXPLAIN一样检查一遍关键操作先备份执行之前再SELECT确认一次目标。在命令行里还可以用事务把多个DDL语句包裹起来这样一旦出错可以ROLLBACK回滚注意MySQL的DDL支持情况取决于版本5.7和8.0对DDL事务性的支持不完全相同所以还是要以备份为主。6.4 库操作常见错误一览表这里整理一份库操作阶段最常见的错误提示和解决方法建议截图收藏。错误码/提示原因解决方法ERROR 1044 (42000): Access denied当前用户无权限操作目标库检查用户权限用管理员授权或切换用户ERROR 1049 (42000): Unknown database库不存在或名字写错用SHOW DATABASES确认库名ERROR 1007 (HY000): Cant create database; database exists重复创建同名库未加IF NOT EXISTS加IF NOT EXISTS或换库名ERROR 1008 (HY000): Cant drop database; database doesnt exist删除不存在的库未加IF EXISTS加IF EXISTS或先确认库名ERROR 1064 (42000): You have an error in your SQL syntaxSQL语法写错仔细检查符号、空格、关键字ERROR 2002 (HY000): Cant connect to local MySQL server through socket服务未启动或socket路径不对启动服务/检查配置文件ERROR 1130 (HY000): Host not allowed to connect to this MySQL server用户不允许从当前IP连接修改用户Host为%或指定IP7. 实践中总结的几条库管理心得7.1 建库脚本应当符合规范并且可重复执行我在实际项目里建库脚本一般单独放在项目根目录的sql文件夹下命名清晰区分“全量初始化”和“增量变更”。每条建库语句都加上幂等保护也就是IF NOT EXISTS、IF EXISTS从句这样即使脚本被重复执行也不会报错。这一步看似多余但在自动化部署和多人协作时能减少大量沟通成本。一个规范的项目级建库脚本大概长这样CREATE DATABASE IF NOT EXISTS school DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; USE school;对的你没看错最基础的脚本就这两条。真正复杂的表结构都拆到变更文件里用版本号管理而不是一股脑全写在一个文件里。这个习惯让我少踩了很多“生产环境执行顺序不对”的坑。7.2 备份策略要趁早养成不要等出事了再补备份这东西属于典型的“用时方恨少”。我的建议是哪怕你只是在学习阶段也值得从第一天就养成备份习惯。最简单的备份方式就是mysqldumpmysqldump -u root -p school school_backup.sql这条命令把school库的所有结构和数据导出到一个SQL文件里。恢复时执行mysql -u root -p school school_backup.sql恢复前需要保证school库已经存在可以先执行CREATE DATABASE否则MySQL会因为找不到目标库而报错。日常开发中我习惯在每次重大改动前做一次备份哪怕只是加一个字段因为谁也不知道这条ALTER语句会不会引发连锁反应。7.3 命名规范是一个低成本高回报的习惯关于库名不同公司风格不同有的用业务领域名比如order_db、user_db有的用项目代号加环境后缀比如project_dev、project_prod。我个人推荐一个原则库名要能一眼看出是干什么的同时区分环境。比如你同时在开发环境和生产环境跑同一个项目库名就可以区分成school_dev和school_prod。这样哪怕忘记看配置文件里的环境标志只要看到库名就能知道自己在操作哪套数据能避免相当一部分误操作事故。8. 从库操作通往下一阶段的路线图到这里你已经把MySQL最底层的“库”这一块摸得差不多了。再往下走就是打开这个库去操作里面的表和数据了。表结构的字段类型选择、索引设计、增删改查语句优化、事务隔离级别、锁机制每一个都是大坑也是真正拉开开发水平和薪资差距的地方。但我仍然建议你在进入这些高阶话题前先把库这个层面的操作练到条件反射的程度。因为后续所有技能的验证都依赖一个稳定、正确的库环境。你总不想在测试索引性能的时候因为库的字符集不对导致中文字段乱码然后花半天时间去排查环境问题吧个人经验是把库的增删改查、字符集选择、用户授权、备份恢复这四个模块练熟基本就能应付绝大多数日常开发场景了。至于更深入的数据目录结构、bin log、undo log、redo log这些底层机制等你实际运维过一段时间的MySQL之后再研究理解会深刻得多。最后再分享一个实用的小技巧新环境拿到手第一步永远是SHOW VARIABLES LIKE %version%;和SHOW VARIABLES LIKE character%;先摸清版本和字符集的底细再动手建库建表。这个习惯帮我避掉了无数由于环境差异引起的低级问题也推荐给你。
返回列表