不少朋友都催我出一份MySQL的基础笔记说网上的教程要么太长、要么太散看着头疼。这篇就是我平时带新人时随手整理的“不全版”——只挑干活最常用的东西不扯太深的理论把建库、增删改查、事务、锁、导入导出这些基础操作讲明白顺便把我这些年踩过的坑也一并写了。适合刚接触数据库、或者用过但没系统梳理过的同学可以直接当手册查也可以按着往下敲。MySQL这东西说白了就是一个存数据的仓库而且是目前全球用得最广的开源关系型数据库之一。不论你是做Java后端、Python数据分析还是自己搭个小网站基本都绕不开它。我这篇笔记不打算从“数据库发展史”讲起那没意思。咱们直接进入正题MySQL怎么装、怎么用、怎么避免把线上搞挂。1. MySQL是什么为什么大家都在用1.1 先搞清楚数据库、表和记录的关系很多人刚开始学的时候容易把“数据库”“表”“记录”这三个词搞混。我习惯用一个类比数据库就像一个大仓库仓库里有很多货架表每个货架上放着规格统一的货箱记录。一个数据库可以有很多张表每张表用来存同一类数据。比如一张用户表里面每一行就是一个用户每一列就是这个用户的一个属性比如用户名、邮箱、注册时间。在MySQL里你输入一条SQL语句其实就是在操作这些表和记录。理解这个层级关系之后很多语法就不难背了。比如“查询”就是“从某张表里找符合条件的行”“删除”就是“把某些行从表里移除”。顺序不能乱先建库再建表然后才能往里插数据。MySQL是个典型的关系型数据库数据以“表格”的形式组织并且表跟表之间可以建立关联。比如订单表通过“用户ID”关联用户表这样就能查某个用户的所有订单。这种设计让数据整洁、不重复也方便做统计。相比一些NoSQL数据库比如MongoDB、RedisMySQL的强项在于强一致性和复杂查询适合业务逻辑里需要严格对账、多条件联查的场景。1.2 版本选择5.7和8.0到底怎么选如果你去MySQL官网看下载页面会发现主要提供两个大版本5.7和8.0。5.7是一代经典运行稳定老项目里用得特别多8.0是现在的大版本默认字符集改成了utf8mb4性能和安全也更好还加入了窗口函数、公用表表达式CTE这些新特性。我的建议是新项目无脑选8.0别再用5.7了。原因很直接8.0已经发布好几年生态成熟网上资料也多。5.7的官方支持已经步入倒计时而且它默认的字符集还是utf8mb4的话需要自己配置但8.0开箱即是。如果你跟我一样经常要跟老系统打交道那就两套都装用端口或者服务名区分。比如我本机就装了MySQL 5.7和8.0一个跑3306一个跑3307互不干扰。另外很多人问下载zip包还是msi安装包。Windows下msi是图形界面一路点“下一步”省心zip是绿色版解压后自己初始化好处是可移植、不写注册表。我个人更喜欢zip因为团队里要统一版本时直接把整个目录压缩传给别人就能用但前提是你记得怎么初始化。下面专门写一下。2. 安装与初始化Windows和Linux两种姿势2.1 Windows下用zip包安装MySQL 8.0别嫌麻烦zip包的安装其实就三步解压、初始化、启动服务。我第一次装的时候在网上找教程看到一堆参数直接被劝退后来自己试通了才发现没那么玄乎。首先去MySQL官网下载zip包注意选“Windows (x86, 64-bit), ZIP Archive”那个别下成Debug版。解压到打算安装的位置比如C盘或者D盘路径里尽量不要带中文和空格。然后以管理员身份打开CMD进入解压后的bin目录执行mysqld --initialize-insecure这条命令会初始化数据目录默认在解压目录下的data文件夹里--initialize-insecure的意思是初始化后root用户没有密码。如果你用--initialize会随机生成一个临时密码还得去日志里翻对新手不友好。所以我建议先用--initialize-insecure起来之后再自己改密码。接着把MySQL注册成Windows服务这样以后不用每次都手动启动mysqld --install MySQL80 net start MySQL80如果一切正常服务就起来了。此时用mysql -uroot -p密码直接回车就能进入MySQL命令行。进去第一件事就是改密码ALTER USER rootlocalhost IDENTIFIED BY 你的新密码;注意新版本MySQL默认使用caching_sha2_password插件部分老客户端可能连不上。如果遇到这种问题可以在改密码时指定使用mysql_native_password后面章节再细说。2.2 Linux下用rpm或tar包安装Linux服务器上最常见的两种装法就是用yum/rpm自动装或者下载tar包手动部署。yum装最省事以CentOS为例wget https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm rpm -ivh mysql80-community-release-el7-7.noarch.rpm yum install mysql-community-server systemctl start mysqld装完后MySQL会自动生成一个临时密码写在日志文件里一般是/var/log/mysqld.log。用grep temporary password /var/log/mysqld.log就能看到。然后执行mysql -uroot -p输入临时密码登录进去后马上要改密码ALTER USER rootlocalhost IDENTIFIED BY 新密码;注意新密码必须符合MySQL的密码策略太简单会直接报错。如果不想那么严格先改成复杂密码再通过validate_password相关参数调低即可。tar包安装的流程跟Windows zip差不多解压、初始化、启动。不过Linux下要专门建一个mysql系统用户来跑还要把data目录的权限归属于这个用户不然会启动失败。这一步别看简单我见过不少人在mysqld_safe那一步卡住日志里提示权限不足其实就是目录owner不对。2.3 初始化的两个坑字符集和大小写敏感几乎所有新手安装后都会遇到乱码问题。原因很简单早期MySQL默认字符集是latin1不是utf8。虽然8.0默认改成了utf8mb4但5.7或者老库升级上来仍然可能沿用旧设置。我建议在服务端配置文件里把字符集写死[mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_0900_ai_ciLinux下配置文件是/etc/my.cnfWindows下是my.ini在解压目录或数据目录附近。改完之后重启MySQL服务才生效。注意utf8mb4和utf8的区别utf8mb4支持emoji和生僻字是utf8的超集。现在建库建表统一用utf8mb4准没错。另一个容易被忽略的是“大小写敏感”。MySQL在Linux下数据库名和表名区分大小写在Windows下默认不区分。这个差异会导致同一个项目开发环境跑得好好的部署到Linux上一查表就报“Table doesnt exist”。如果想统一可以在配置文件里加一行lower_case_table_names1意思是表名存储为小写比较时不区分大小写。这个参数只能在初始化之前改初始化之后修改会有很多奇怪问题所以最好是建库前就决定好。3. 最常用的增删改查CRUD3.1 建库建表的基本语法增删改查是数据库使用频率最高的操作也是很多面试题喜欢考察的点。先看建库CREATE DATABASE IF NOT EXISTS mydb DEFAULT CHARACTER SET utf8mb4; USE mydb;建表就得写清楚每个字段的类型、约束、默认值。拿一张简单的用户表举例CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, email VARCHAR(100) DEFAULT NULL, age INT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_email (email) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里面有几个点值得解释。AUTO_INCREMENT是自增主键插入数据时不用自己填id。DEFAULT CURRENT_TIMESTAMP表示插入时自动带当前时间不用手动写NOW()。ENGINEInnoDB指定存储引擎InnoDB支持事务和外键是现在的主流选择老的MyISAM不支持事务除非有特殊需求否则别用它。当你需要修改一张已存在的表的结构时用ALTER TABLE。比如给user表加一个字段ALTER TABLE user ADD COLUMN phone VARCHAR(20) DEFAULT NULL;修改字段默认值也很容易踩坑。比如想把age默认值改为0ALTER TABLE user ALTER COLUMN age SET DEFAULT 0;如果你的表已经有很多数据ALTER操作会比较耗时而且可能锁表。在低峰期执行并且提前备份这是铁律。3.2 插入、查询、更新、删除的注意点插入数据的标准写法INSERT INTO user (name, email, age) VALUES (张三, zhangsanexample.com, 25);查询是最灵活的随便列几个常用场景-- 全字段查询 SELECT * FROM user; -- 条件查询 SELECT id, name FROM user WHERE age 20; -- 多条件 SELECT * FROM user WHERE age 20 AND name LIKE 张%;这里的%是通配符表示任意长度字符。LIKE查询如果写在开头比如%张是没法走索引的数据量大时性能很差。这点后面说性能的时候会再提。更新和删除一定要带WHERE这句话我每次讲课都要重复三遍。没带WHERE的UPDATE和DELETE会作用到整张表的所有行UPDATE user SET age age 1 WHERE id 10086; DELETE FROM user WHERE id 10086;如果你只想清空表数据不要用DELETE FROM user那样要一条条删、效率低并且自增id不会重置。直接改用TRUNCATE TABLE user它是把整张表的重建一遍速度极快而且自增id会从1重新开始。但TRUNCATE没法回滚用之前想清楚。我见过有人手滑把生产环境的表TRUNCATE了当时一群人差点当场去世最后靠备份才恢复。所以重要表务必定期备份。3.3 排序、分页和去重的坑排序用ORDER BY默认升序ASC降序用DESCSELECT * FROM user ORDER BY created_at DESC;分页用LIMIT它是MySQL的特色。比如每页10条查第3页有两种写法-- 偏移量从0开始跳过20条取10条 SELECT * FROM user ORDER BY created_at DESC LIMIT 20, 10; -- 或者用LIMIT offset, count同样的效果 SELECT * FROM user ORDER BY created_at DESC LIMIT 10 OFFSET 20;分页最常被问到的面试题是“深分页”问题。比如LIMIT 1000000, 10MySQL会先读取前1000010条记录然后丢弃前面的100万条再返回最后10条。数据量一大翻到几百页之后就会明显变慢。解决办法通常是用“延迟关联”或“游标分页”。延迟关联的思路是先查主键id再回表取数据SELECT u.* FROM user u JOIN (SELECT id FROM user ORDER BY created_at DESC LIMIT 1000000, 10) tmp ON u.id tmp.id;游标分页则是在翻页时记录上一页最后一条记录的id下一页用WHERE id 上一页最大id ORDER BY id LIMIT 10。这种写法看起来有点绕但线上大表分页最好用游标体验差距非常明显。去重有两种方式DISTINCT和GROUP BY。如果你的目的是去掉重复行看有哪些取值用DISTINCT如果还要对每组做统计那必须用GROUP BY。比如统计每个年龄的人数SELECT age, COUNT(*) FROM user GROUP BY age;注意WHERE是在分组前过滤HAVING是在分组后过滤。想筛掉人数小于5的年龄段得写SELECT age, COUNT(*) AS cnt FROM user GROUP BY age HAVING cnt 5;这里还有个经典陷阱在SELECT里写的字段如果不是聚合函数里的字段也没出现在GROUP BY里面MySQL的ONLY_FULL_GROUP_BY模式会直接报错。5.7之后默认开启坑了不少从老版本过来的人。解决办法说白了就是别查那些没被分组的字段如果确实需要要考虑用子查询或者ANY_VALUE。4. 事务与锁并发下的底线4.1 事务的ACID和隔离级别事务是MySQL里非常重要但又容易理解偏的概念。简单说事务就是把一组SQL操作打包成一个“不可拆分的单元”要么全部成功要么全部失败。经典的场景就是转账A账户扣钱和B账户加钱必须同时成功不能只成功一半。事务有四个特性简称ACID原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability。很多初级开发者能背出这四个词但真要解释就卡壳。我用大白话讲原子性就是“要么全做要么全不做”一致性就是“做完之后数据仍然符合所有规则”隔离性就是“多个事务同时跑时互不捣乱”持久性就是“只要提交了数据不会因为宕机而丢”。MySQL的InnoDB引擎通过redo log重做日志保证持久性通过undo log回滚日志和锁来保证原子性和隔离性。那“隔离”到什么程度SQL标准定义了四种隔离级别从宽松到严格依次是读未提交READ UNCOMMITTED、读已提交READ COMMITTED、可重复读REPEATABLE READ、串行化SERIALIZABLE。MySQL默认的隔离级别是“可重复读”。这跟Oracle、PostgreSQL默认的“读已提交”不一样面试时经常被问。可重复读意味着在同一个事务里你多次执行同一条SELECT得到的结果是一致的即使其他事务已经提交了新数据。这个特性主要靠MVCC多版本并发控制实现也就是每一行数据存了多个版本查询时根据事务的快照决定看到哪个版本。而“读已提交”只能保证读到的是提交过的数据但可重复读级别下同一个事务内两次相同查询可能结果不同因为第一次读到的快照和第二次读到的快照可能不同。那么问题来了MySQL默认的可重复读是如何解决“幻读”的呢它并不是完全避免了幻读而是通过间隙锁Gap Lock在特定的条件下控制了新行的插入。比如事务里锁定一个范围别的事务往这个范围插数据就会被阻塞。四种级别的影响不用死记你只要记住两件事第一读未提交几乎不用因为可能读到别人还没提交的数据第二串行化性能太差除非对一致性要求极端严格否则生产环境基本不用。绝大多数场景MySQL默认的可重复读足够稳定Oracle用户迁移过来要注意行为差异。4.2 锁的分类和死锁排查关于锁网上有各种分类容易把人绕晕。我按两个维度拆开讲。第一个维度是“锁的对象”。MySQL的InnoDB锁既可以是表锁也可以是行锁。表锁直接锁住整张表粒度大、并发差行锁锁的是单行记录粒度小、并发好。但行锁是用在索引上的如果查询条件不走索引InnoDB就会把全表的所有记录都锁住表面是行锁实际变成表锁性能立刻崩。这就是为什么我们总强调WHERE条件里的字段要有索引。第二个维度是“锁的性质”。分两类共享锁S锁和排他锁X锁。共享锁之间不互斥多个事务可以同时读同一行共享锁和排他锁互斥一个事务读取时另一个事务不能修改排他锁和排他锁也互斥。普通SELECT不加锁靠MVCC读快照SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE才会显式加锁。更新、删除操作会自动加排他锁。死锁又是怎么回事简单说事务A先锁了行1想再锁行2事务B先锁了行2想再锁行1。两边都在等对方释放谁也不让谁就死锁了。MySQL检测到死锁会随机选择一方回滚并报一个deadlock相关的错误。排查死锁时先看最近一次死锁日志SHOW ENGINE INNODB STATUS;里面会有死锁事务的详细信息重点看“LATEST DETECTED DEADLOCK”这一段它会告诉你两个事务分别持有哪把锁、等待哪把锁以及执行的SQL。绝大多数死锁原因就俩一个是加锁顺序不一致另一个是索引没走对导致锁范围扩大。解决死锁的经验是让所有事务访问多张表或同一组行时按照固定的顺序进行。比如先更新用户表再更新订单表那么所有事务都这么做破坏循环等待的前提。另一个就是尽量减少大事务事务里锁的行越多、时间越长死锁概率越高。4.3 事务使用中的几个常见误区第一个误区以为BEGIN之后就一定安全。其实MySQL默认是自动提交的每条SQL都是独立事务。写BEGIN或START TRANSACTION之后必须COMMIT才算真正把事务提交否则连接断开时没提交的变更会被回滚。有人写代码时忘了提交自己测试看着数据变了但程序一重启全没了就是这个原因。第二个误区在事务里做大量查询。严格来说这不叫错但会拉长事务时间导致锁持有太久影响其他并发事务。我见过一个报表任务开启事务后循环查了几千次把一张核心表锁了十几分钟直接把在线业务干停了。事务应该“快进快出”写事务的SQL要尽量精简把无关查询放到事务外面。第三个误区对ROLLBACK的依赖太强。虽然回滚能撤销未提交的修改但有些操作回滚不了。比如AUTO_INCREMENT自增id一旦消费就不会回退即使事务回滚了id照样跳号。还有DDL建表、ALTER、DROP操作在MySQL默认情况下不能回滚Oracle里可以MySQL不行。很多人不知道这一点执行DROP TABLE之前没备份想回滚直接傻眼。记住DROP和TRUNCATE无法通过事务回滚只能靠备份恢复。5. 存储过程、导入导出与常用工具5.1 存储过程怎么写才实用存储过程就是一段预编译的SQL逻辑保存在数据库里可以反复调用。在业务代码里写复杂SQL不如把一部分固定的数据处理逻辑放到存储过程里。比如一个批量更新用户积分的操作就可以写成存储过程。它的好处是减少网络传输、逻辑集中管理缺点是不好调试、版本管理麻烦。我的原则是逻辑复杂的业务计算尽量放在应用代码里只有对性能要求极高且固定的批量操作才考虑用存储过程。一个简单示例创建一个给指定用户加积分的存储过程DELIMITER // CREATE PROCEDURE add_bonus(IN p_user_id INT, IN p_points INT) BEGIN UPDATE user SET points points p_points WHERE id p_user_id; END // DELIMITER ;这里DELIMITER是为了告诉MySQL客户端存储过程内部的;不要提前截断等见到//才算结束。调用方式也很简单CALL add_bonus(1, 100);写存储过程最容易忽略的是“边界条件”。比如p_points是负数怎么办用户不存在时要不要报错我建议在存储过程开头加校验用IF判断不满足条件就SIGNAL抛异常避免脏数据。另外存储过程中如果涉及动态SQL一定要小心SQL注入拼接变量前先验证参数类型和取值范围。如果你在Linux服务器上直接执行一个.sql文件来创建存储过程注意文件里的DELIMITER同样有效。如果用Navicat之类的工具通常不需要手动写DELIMITER工具会自动处理。5.2 数据导入导出的几种姿势导入导出几乎是每天都要用的操作。最简单的是用mysqldump导出整个库mysqldump -uroot -p --single-transaction --default-character-setutf8mb4 mydb mydb_backup.sql--single-transaction参数的意思是以一个事务做一致性快照避免导出时阻塞线上的写操作特别适合InnoDB表。如果不加它默认会锁表并发高的库会被打一大截。恢复数据就是把这个sql文件导进去mysql -uroot -p mydb mydb_backup.sql或者进入MySQL后SOURCEUSE mydb; SOURCE /path/to/mydb_backup.sql;说一句题外话mysqldump导出的文件其实是SQL文本可以用记事本打开看通常包含DROP TABLE IF EXISTS和CREATE TABLE语句所以导入时会先清掉老表再建新表。如果你想保留旧表导入前最好先备份。除了mysqldump现在还有两个比较流行的工具mydumper和Xtrabackup。mydumper支持并行导出速度比mysqldump快很多适合超大库。Xtrabackup则擅长物理备份直接拷贝数据文件适合全量备份和增量备份。如果你用过MySQL官方的企业版备份工具会发现原理也是类似的。日常小库用mysqldump就够几G的库建议上mydumper。导入导出Excel的场景也很常见比如把Excel数据导入数据库。这个一般用的工具是Navicat的“导入向导”或者用Python的pandas写脚本。核心注意点是Excel里的日期格式、空值和状态码。日期建议转成字符串比如yyyy-MM-dd HH:mm:ss避免时区问题空值可以用NULL替代。还有一个很坑的地方如果Excel里有“序号”列导入时一定要删掉不然就多了一列重复数据。5.3 常用工具软件怎么选命令行是必须会用的但日常开发时我一般用图形化客户端提高效率。Windows下最常用的是Navicat和DBeaver。Navicat收费但功能齐全傻瓜式操作DBeaver是开源的免费工具基于Java支持几乎所有数据库。如果你追求免费DBeaver绝对够用。另外还有MySQL官方的Workbench虽然界面有点笨重但胜在完全免费、有微软VC之类的依赖要求不高适合不装额外工具的场景。手机上有时候也想临时看数据库iOS上有人用“SQLPro”之类的客户端但不如电脑上方便。我自己还是习惯把常用查询存成文本片段随时复制。顺便提一句见到网上有人提什么“dbx数据库工具”我没用过不敢乱推荐但如果是作为Navicat的替代品大概率也是类似功能。工具这东西选自己用得顺手的就好不要哪个好换成哪个。6. 踩坑记录与排查思路6.1 连接不上数据库从哪里入手这是新手求助最多的一类问题。现象各不相同有报“Cant connect to MySQL server”有报“Access denied for user”还有报“Unknown database”。排查思路其实是有套路的。第一先确认MySQL服务在不在跑。Windows下看服务列表里的MySQL服务状态Linux下用systemctl status mysqld或ps -ef | grep mysqld。如果是Docker部署还要看容器是否起来了。很多连接失败的根因就是服务没起来或者被防火墙挡了端口。第二确认网络和端口。默认端口3306如果你在别的机器上连要确保MySQL配置里的bind-address不是127.0.0.1并且防火墙放行了3306端口。云服务器还要检查安全组规则。如果是本机测试直接连localhost就行。另外一个隐蔽的点是MySQL的skip-networking参数一旦开启就只能通过socket连接TCP连接全部失败。第三确认账号权限。MySQL的账号是由“用户名 主机”组成比如rootlocalhost和root192.168.1.%是两个不同的账号。如果你在另一台机器上连但只授权了localhost那肯定报拒绝。授权方式CREATE USER appuser192.168.1.% IDENTIFIED BY 密码; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO appuser192.168.1.%; FLUSH PRIVILEGES;注意FLUSH PRIVILEGES在改过系统表权限后要用一下否则可能不生效。如果是改密码导致的原连接报错那需要检查客户端的连接协议新版MySQL默认的caching_sha2_password插件对老客户端不友好解决办法是ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 新密码;6.2 查询变慢先从这几个方向查慢查询是性能问题里最常见的一类。第一步就是开慢查询日志看看是不是有某条SQL长时间占着资源。MySQL里有个参数long_query_time单位为秒默认10秒生产一般设成1秒甚至更短。查看是否开启SHOW VARIABLES LIKE slow_query_log;然后重点分析是不是没走索引用EXPLAIN看执行计划EXPLAIN SELECT * FROM user WHERE email zhangsanexample.com;看key列如果显示NULL说明没用到索引。再看type列如果是ALL表示全表扫描那铁定慢。解决办法就是建索引CREATE INDEX idx_email ON user(email);不过索引也别乱建。索引是拿空间换时间而且每个索引都会拖慢写入速度。一张表建七八个索引很正常但如果建了永远用不到的索引纯粹是浪费。怎么知道哪些索引没用MySQL 8.0有sys.schema_unused_indexes视图能直接查。还有一种慢是因为语句写法有问题。比如对索引列做了函数运算WHERE YEAR(created_at) 2024这样索引就失效了应该改成范围查询WHERE created_at 2024-01-01 AND created_at 2025-01-01。再比如隐式类型转换字段是字符串类型你却传入数字MySQL会偷偷把字段转成数字再比较同样用不上索引。这些细节从执行计划里都能看出来。最后表数据量太大的话需要考虑分库分表或者归档。MySQL单表在千万级仍然可以靠优化撑住但如果上亿索引再合适也是硬扛。遇到这种情况建议做分区表或者把历史数据迁移到冷库让热表保持轻量。6.3 备份与恢复别等出事才想备份这事平时没人当回事一旦误删数据就是天塌下来。我自己的原则非常简单重要库每天至少一次全量备份开着binlog做增量备份。binlog是MySQL的二进制日志记录了所有数据变更通过它可以把数据库恢复到一个时间点。开启binlog只需要在配置文件里加[mysqld] log-binmysql-bin server-id1 binlog_formatROW然后重启MySQL。之后每次数据变更都会写进binlog。恢复的时候先用最近的物理或逻辑备份把库恢复到某个时间点再通过binlog把之后的操作重放。这个过程比较繁琐但确实能在不小心执行了没带WHERE的DELETE之后救人一命。我还遇到过奇葩情况Docker环境里跑MySQL因为时区或者挂载卷配置不当数据文件损坏。所以用Docker跑数据库一定要把数据目录挂载到宿主机每次启动新容器要保证数据卷还在。不然docker rm删容器的时候数据也跟着没了那真是欲哭无泪。你还可以用docker run -v /my/data:/var/lib/mysql这种形式挂载。再说一个容易被忽略的点mysql_upgrade或者mysqlcheck。在升级MySQL大版本后旧表结构可能不兼容需要执行mysql_upgrade来检查并修复系统表和视图。这个操作不能跳过否则可能会遇到诡异的报错。最后再分享一句经验这篇笔记在“不全”的路上走得很刻意因为数据库知识学无止境真全起来可以写好几本书。上面这些内容是我在维护线上系统中反复用到、也反复踩坑后的沉淀。如果你能把建库建表、CRUD、事务隔离、索引和备份这几件事做扎实日常开发已经够用了。后续如果再遇到具体问题比如分库分表、死锁分析、高可用架构那都是建立在这些基础之上的上层建筑。基础不牢后面越写越痛苦。慢慢啃多动手把命令敲进MySQL里亲自看结果比看一百篇文章都管用。
阅读完成 · 觉得有帮助?