ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

MySQL新手实战:从安装到上线的避坑全指南

MySQL新手实战:从安装到上线的避坑全指南 如果你正在读这篇文章大概率你现在就处在“第一次碰MySQL”的状态。我到现在都记得自己第一次装MySQL时的狼狈从官网下载了zip包解压完不知道下一步该干嘛照着网上一篇文章配了my.ini结果net start mysql直接报“服务无法启动”我盯着黑窗口愣了半小时后来才发现是data目录没初始化的原因。这篇文章不是把官方文档换个说法念给你听而是把我从下载、初始化、启动、建表、写事务、再把MySQL接进项目这条线上踩过的坑按“第一次会遇到什么”的顺序完整捋一遍。不管你是为了上课、写毕业设计还是刚入职要接手一个JavaWeb项目照着这个顺序走能少走很多冤枉路。1. 第一次装MySQL版本、安装包、环境准备一次到位1.1 版本与发行包的选择8.0不是盲目跟风第一次接触MySQL的人很容易在版本上纠结。网上教程经常互相打架有人让你装5.7因为“稳定”有人让你装8.0因为“新”。我的建议很直接全新项目一律装MySQL 8.0除非公司老系统明确写了只能用5.7。为什么8.0相比5.7有几个不可忽视的优势默认字符集是utf8mb4对中文和表情符号更友好窗口函数、CTE公共表表达式这些写复杂查询很好用InnoDB引擎进一步强化性能和数据安全都更好。更关键的是很多新工具和云服务已经默认按8.0的协议来对接你装个5.7反而可能遇到兼容问题。还有一个容易被忽略的点网卡之前先搞清楚自己机器是什么架构。普通Windows电脑基本是x86_64Linux服务器可能是x86_64也可能是arm64。比如你在ARM架构的Linux服务器上装MySQL 5.7能找到的安装包和依赖往往非常老装起来全是坑。遇到这种环境优先选8.0的官方ARM包或者干脆用Docker跑官方镜像。1.2 Windows下zip包安装my.ini、初始化、注册服务Windows上安装MySQL有两条路一是用官方图形安装包msi全程点下一步二是下载解压版zip包自己手动配置。我强烈建议新手至少手动走一遍zip包安装因为只有手动配置过你才能真正知道MySQL的服务、数据目录、配置文件之间是什么关系以后出问题排查才有方向。具体步骤很简单但每一步都有坑。第一步去官网下载mysql-8.0.x-winx64.zip别去各种软件站下疯狂捆绑的绿色版。解压到一个路径里不要带中文、不要带空格比如D:\mysql-8.0.44-winx64。第二步在解压目录下新建my.ini配置文件。最小可用配置长这样[mysqld] basedirD:/mysql-8.0.44-winx64 datadirD:/mysql-8.0.44-winx64/data port3306 character-set-serverutf8mb4 collation-serverutf8mb4_general_ci这里最容易踩的坑有两个一是basedir和datadir的写法很多教程用反斜杠\结果字符串被转义后路径识别不了建议统一用正斜杠二是只写了配置却没执行初始化就直接启动服务结果服务起来就崩。第三步以管理员身份打开命令提示符进入MySQL解压目录的bin目录执行mysqld --initialize-insecure --console这条命令会生成data数据目录。--initialize-insecure表示初始化后root用户没有密码方便第一次登录如果去掉insecureMySQL会自动生成一串随机密码写在日志里新手很容易找不到它。第四步注册Windows服务mysqld --install MySQL net start mysql到这一步如果你前面都做对了服务能正常启动说明MySQL已经跑起来了。注意net start mysql里的服务名要跟你mysqld --install后面写的名字一致不然Windows会提示“服务名无效”。1.3 Linux和Docker环境下的安装路线Linux服务器上的第一次安装最常用的是rpm包方式。CentOS、Rocky Linux这类系统上装MySQL最大的前提是先处理掉系统自带的MariaDB两个一起装会抢占3306端口和/usr/lib64/libmysql*库文件。简单说下rpm安装链路# 先查一下有没有装了mariadb rpm -qa | grep mariadb # 有就卸载 yum remove -y mariadb-libs # 安装官方rpm包版本号按实际下载来 rpm -ivh mysql-community-server-8.0.44-1.el9.x86_64.rpm # 启动服务 systemctl start mysqld systemctl status mysqldLinux上用rpm方式装MySQL有一个特殊点服务启动时MySQL会自动做数据目录初始化并把临时密码写到/var/log/mysqld.log里。第一次登录要用grep temporary password /var/log/mysqld.log把临时密码捞出来。如果服务器不能联网就得走离线安装。提前把rpm包和所有依赖包下载到内网机器上按顺序rpm -ivh装依赖用rpm -Uvh --nodeps强行装容易出问题实在缺哪个就单独补哪个。Docker也是一种很主流的方式特别适合本地开发docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD你的密码 \ -e TZAsia/Shanghai \ -v mysql-data:/var/lib/mysql \ mysql:8.0Docker安装失败最常见的原因是端口被占用宿主机上已经有别的进程占了3306端口。先在docker run之前用netstat -ano | findstr :3306检查一下别等启动失败再去排查。还有一个坑是数据目录的权限容器里的mysql用户对挂载目录没写权限会直接退出chmod 777不优雅但能快速验证生产环境建议用--user参数配合命名卷来解决。2. 服务起不来、密码连不上第一次启动最常见的两座山2.1 “net start mysql”服务无法启动的排查链路注意下面所有内容围绕解决net start mysql 系统发生错误 2/5/1067这类问题。每次看到“服务无法启动”我的第一反应不是你配置文件写错了而是先去找错误日志。MySQL的错误日志路径写在my.ini的log-error参数里如果没写默认在datadir目录下文件名类似.err。Windows下也可以用事件查看器Linux下看journalctl -u mysqld。把日志打开之后重点关注三种情况。第一种日志里报[ERROR] Cant find message-file或者路径找不到基本就是my.ini里的basedir和datadir写错了路径不存在。Windows的路径分隔符要小心最稳妥的是正斜杠。第二种日志里报[ERROR] InnoDB... Permission denied这是权限问题。Windows上多半是数据目录的权限不够比如把MySQL装在C:\Program Files下而data目录没有给mysql用户写权限Linux下则要chown -R mysql:mysql /var/lib/mysql。第三种端口被占用。日志里会有[ERROR] Could not open TCP port 3306。这个需要在命令行执行netstat -ano | findstr :3306看PID是多少然后去任务管理器里结束对应进程。有可能占用3306的是另一个mysqld实例也可能是你用Docker起了一个MySQL把宿主机的3306占了。我遇到过一个特别“诡异”的情况Windows服务起不来事件查看器里报了一个托管异常码e0434352。我当时没有在my.ini里深挖而是把服务删了重新注册一遍又把杀毒软件对MySQL整个目录的实时扫描关掉服务就正常了。这个经验就是服务起不来别猜先看日志看日志解决不了往系统环境、杀毒软件、运行库方向想最后再考虑重装。2.2 root密码不是忘了是根本还没设置第一次登录MySQL最让人懵的就是root密码。如果你用的是mysqld --initialize-insecure那root初始没有密码直接回车就能登录mysql -uroot -p如果用的是rpm方式安装或者mysqld --initialize初始密码是临时生成的。用下面命令找回grep temporary password /var/log/mysqld.log登录进去之后第一件事就是改root密码同时创建一个平时开发用的普通账号。这样做的原因是永远不要用root干业务活万一连接串泄露root权限等于把整个库都暴露了。改密码和建账号的SQL如下ALTER USER rootlocalhost IDENTIFIED BY 新密码; CREATE USER dev% IDENTIFIED BY dev密码; GRANT ALL PRIVILEGES ON *.* TO dev%; FLUSH PRIVILEGES;注意MySQL 8.0默认的认证插件是caching_sha2_password如果你的客户端特别老登录时可能报Authentication plugin caching_sha2_password cannot be loaded。解决办法有两个升级客户端驱动或者给那个用户指定旧插件CREATE USER oldclient% IDENTIFIED WITH mysql_native_password BY 密码;现在基本都在用新驱动了但还是要知道这个坑因为你接老项目时随时可能碰上。2.3 客户端连接报SSL错误随手加上useSSLfalse就行很多教程里JDBC连接串随手就是useSSLfalse新手照抄之后SSL错误确实消失了但压根不知道自己在做什么。先说结论这个报错“SSL connection error: protocol version mismatch”绝大多数情况不是MySQL配错了而是客户端和MySQL支持的TLS协议版本对不上。MySQL 8.0默认开启SSL要求客户端使用TLS 1.2以上老版本驱动用TLS 1.0去握手自然失败。如果只是本地开发、没有涉及敏感数据useSSLfalse是可以接受的临时方案。但一旦部署到公网或者公司安全审计要求加密传输就必须把SSL配好。实现方式是让客户端信任MySQL服务器的CA证书在驱动里指上sslModeVERIFY_CA和serverSslCert参数。另一个因为SSL连带出现的报错是Public Key Retrieval is not allowed。这是MySQL 8.0的caching_sha2_password插件在非SSL连接下需要先把服务器的公钥拉下来。解决办法是连接串加allowPublicKeyRetrievaltrue。这个参数的意义就是告诉驱动“我允许你获取公钥”本地开发可以开生产环境还是要优先走SSL别把这个参数当成万能解药。3. 从建库到建第一张业务表schema、字段、索引一起说清3.1 为什么MySQL特别强调database、schema和table三个概念很多人一开始不理解为什么MySQL的官方文档把database和schema经常混着用。在MySQL里这两个基本是同一个东西CREATE SCHEMA等价于CREATE DATABASE。但在SQL Server、PostgreSQL里schema和database完全是两个层级。你可以把这个关系想成一个小区MySQL实例是整片小区database是其中一栋楼table是楼里的房间。你在MySQL里常做的操作流程是先SHOW DATABASES看有哪些楼然后USE 你选中的数据库;进楼再SHOW TABLES;看这栋楼里有哪些房间。实际项目中一个应用通常对应一个独立database多个表放在里面。不要把不同业务的数据强行塞进同一个库也别给一个应用建十几个库后期权限管理和备份都很痛苦。这是我见过很多“第一次”项目里最常见的混乱。3.2 一张用户表的建表实操与字段默认值讲完概念直接上实操。假设我在写一个商城项目第一张表多半是用户表。先建库再建表CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE shop; CREATE TABLE user ( id BIGINT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录名, password_hash VARCHAR(255) NOT NULL COMMENT 加密后的密码, age INT NOT NULL DEFAULT 0 COMMENT 年龄默认0, email VARCHAR(100) DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB;这里有几个第一次建表时一定要弄明白的点。第一为什么主键用BIGINT AUTO_INCREMENT而不是INT业务小的时候INT也够用但用户万一真的做大了INT上限不到21亿看着很安全可一旦要迁移数据、合并分片BIGINT能省掉很多事。这个选择成本几乎为零为什么不直接选大一点。第二字段默认值是怎么设置的。DEFAULT 0就是给age字段设置默认值为0如果插入时不给值MySQL自动填0。注意把字段定义为NOT NULL DEFAULT 0时你让这个字段“不能为空但给了默认值”这跟“允许NULL但没有默认值”是两种完全不同的语义。搜过“mysql设置默认值为0”这个关键词的朋友十有八九就是在纠结这种细节。第三COMMENT写不写我见过太多第一次建表的人完全不加注释过一个月自己都忘了字段是什么含义。生产环境里字段注释比代码注释还重要建表时一定要写。3.3 索引和排序别等数据多到查询变慢再补课第一次建表的人容易犯一个毛病把所有可能查询的字段都加上索引。结果表不大性能没提升写入倒是慢了。索引的本质是复制一份字段数据并排好序让查询不用全表扫描。一旦你明白这个原理就会知道频繁作为查询条件、并且区分度高的字段适合建索引比如username区分度极低的字段比如性别、状态建索引反而浪费空间。实际开发里最常用的查询性能排查手段是EXPLAINEXPLAIN SELECT id, username FROM user WHERE username 张三;看到typeconst或ref就说明用上索引了看到typeALL就是全表扫描。全表扫描在小表上问题不大到百万级数据就明显卡顿。关于排序中西文环境经常会遇到一个意外看起来明明建了索引但ORDER BY就是不走索引性能很差。原因多半是字符集排序规则问题。MySQL的utf8mb4有utf8mb4_general_ci和utf8mb4_unicode_ci等不同排序规则索引的排序规则和查询要求不一致时优化器只能放弃索引。中文场景用utf8mb4_general_ci排序就够了遇到特殊拼音排序需求再单独处理。3.4 修改表结构ALTER TABLE不只是加个字段而已第一次接线上项目总会碰到“表结构要改了”的需求。最常用的就是加字段ALTER TABLE user ADD COLUMN phone VARCHAR(20) DEFAULT NULL;就这么一句在小表上秒回但如果是一张几千万行的表执行这句ALTER可能会锁住整张表读写很久。MySQL 8.0的在线DDL比5.7更成熟大部分加字段操作可以在线执行不再阻塞写入但这不意味着你可以随便在业务高峰期乱改大表。改列类型或者重命名就更谨慎比如把INT改成BIGINT这个操作会把整表重写耗时和磁盘空间消耗都很高。我第一次操作线上表的时候只改了一个字段类型结果跑了快一上午业务侧不得不做了只读维护。之后养成了习惯大表结构变更之前先用SELECT COUNT(*)和SHOW TABLE STATUS评估行数和表大小再决定是直接改还是用专门的改表工具。顺带提一句如果你做物联网数据采集想把MySQL的表结构自动转成TDengine的超级表和子表思路也是一样的先用information_schema.columns读MySQL的字段定义再映射到TDengine的tag和列字段类型、默认值、注释都得一一对上本质还是先吃透MySQL这套元数据模型。4. 事务、存储过程、触发器和锁第一次写“批量逻辑”的心理准备4.1 事务的四个特性和两个实操动作MySQL最值得花时间理解的就是事务。事务解决的核心问题非常朴素一条转账操作要同时扣A的钱、加B的钱如果只扣了A没加成B那整个账本都乱了。事务的四个特性就是ACID原子性整个事务要么全成功要么全失败。一致性事务执行前后数据都满足约束。隔离性两个事务同时操作同一条数据时互相不干扰。持久性事务提交后即使断电也不会丢。在SQL里体现为START TRANSACTION; UPDATE account SET balance balance - 100 WHERE id 1; UPDATE account SET balance balance 100 WHERE id 2; COMMIT;如果中间任何一步失败你在出错后执行ROLLBACK;两条UPDATE都会被撤销。新手最容易忽略的是默认情况下你随便执行的每条SQL语句都是自动提交的。只有在多语句需要被看成一个整体时才手动START TRANSACTION。另外一个重要前提是只有InnoDB引擎支持事务。如果你的表是MyISAM哪怕写了事务也不生效MySQL会悄悄当单条SQL执行。隔离级别也是个绕不过去的话题。MySQL默认隔离级别是REPEATABLE READ也就是同一事务里你重复查同一条件结果始终一样。不同隔离级别会带来脏读、不可重复读、幻读等不同问题。第一次接触不用背太熟但要能说出四种隔离级别由低到高是读未提交、读已提交、可重复读、串行化能说出MySQL默认是可重复读就够应付多数面试和日常开发了。4.2 存储过程的DELIMITER到底解决什么问题很多新人第一次在MySQL里写存储过程明明照着教程抄却总是报语法错误。别慌多半是你没理解DELIMITER这个命令的意义。MySQL默认用分号作为一条语句的结束符。你写一个存储过程CREATE PROCEDURE p_test() BEGIN SELECT 1; SELECT 2; END;MySQL客户端读到第一个分号就把语句发送到服务器而实际上这个CREATE PROCEDURE还没写完服务器根本无法解析。DELIMITER的作用就是临时告诉MySQL客户端“你别拿分号当结束了用别的符号”。正确写法DELIMITER // CREATE PROCEDURE p_test() BEGIN SELECT 1; SELECT 2; END// DELIMITER ;写完记得把分隔符改回来否则你后面所有正常的SQL语句都会因为找不到结束符而一直等待。存储过程里还经常要处理错误。比如插入数据时遇到主键冲突你可以捕获信号DECLARE EXIT HANDLER FOR 1062 BEGIN SELECT 主键冲突了; END;这里的1062就是MySQL的错误码对应主键重复。熟悉这些错误码对处理后面的“错误信息”类排查很有帮助。4.3 触发器里的分隔符与错误处理触发器和存储过程一样也需要理解分隔符问题。我第一次建触发器时因为漏了DELIMITER被奇怪的报错卡了很久。触发器一个典型的用途是自动维护审计字段DELIMITER $$ CREATE TRIGGER trg_user_before_insert BEFORE INSERT ON user FOR EACH ROW BEGIN SET NEW.created_at NOW(); END$$ DELIMITER ;触发器的BEFORE、AFTER分别表示在事件之前还是之后触达事件通常是INSERT、UPDATE、DELETE三种。触发器的逻辑里不允许返回结果集也不能直接调用存储过程带返回值的部分新手最容易在这上面翻车。我要提醒的是业务逻辑能写在应用层就尽量写在应用层触发器能不用就不用。原因是触发器是隐式的排查问题时你根本想不到某个字段被自动修改是触发器干的。尤其在一个多人维护的项目里一个隐藏的触发器可能让所有人排查到崩溃。只有在做强制审计、多表同步这类必须靠数据库自身保证的约束场景触发器才值得用。4.4 锁表与死锁真实项目里第一次被“卡住”的经历第一次在真实项目里遇到“数据库卡死”大概率就是锁的问题。最经典的一条SQL会阻塞别人UPDATE user SET age 10 WHERE id 1;这条语句执行时会给id1的行加排他锁。如果事务一直没提交其他任何对该行的UPDATE、DELETE都会等待。你在应用里看到的现象就是点击按钮一直转圈代码没有报错数据库连接被占满日志里全是“锁等待超时”。排错思路要清晰。先SHOW PROCESSLIST;看有哪些会话长时间处于Waiting for table metadata lock或者updating状态再用SHOW ENGINE INNODB STATUS;看最近一次死锁的具体SQL最后找到造成阻塞的源头连接用KILL 进程ID;杀掉它。死锁是更严重的情况事务A锁了行1想等行2事务B锁了行2想等行1谁也等不到谁。InnoDB会自动检测死锁并回滚其中一个事务但你的应用必须处理“操作失败、可能导致数据未提交”的回滚逻辑。预防死锁有个非常实用的习惯多个事务如果需要更新多行数据尽量按固定的顺序操作。比如订单一类的业务永远先更新主表再更新明细表死锁概率会大大降低。另外InnoDB的行锁是建立在索引上的如果查询条件没走索引InnoDB就会锁整张表这是另一个常见锁表原因。5. 第一次把MySQL接入真实项目连接池、驱动和客户端得配齐5.1 JDBC连接串参数SSL、时区、公钥获取Java项目接MySQL配置JDBC连接串是绕不开的也是第一次最容易出问题的点。先用一个标准的MySQL 8连接串举例jdbc:mysql://127.0.0.1:3306/shop?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingutf8每个参数都有故事。serverTimezone必须显式指定因为MySQL驱动去读服务器时区时如果机器时区是UTC而你的业务在东八区时间就会差8小时。第一次做完查询发现时间不对头两个月我都没意识到来连接串加时区。characterEncodingutf8是保证中文不乱码的基础。注意这里推荐用utf8mb4时库表级别要把字符集统一设成utf8mb4连接串里写utf8是为了兼容驱动实际取了连接后驱动会自动处理。之前说的SSL错误在JDBC里还涉及到useSSL和allowPublicKeyRetrieval的组合。本地开发useSSLfalse绰绰有余生产环境必须把证书链配好。这个权衡反复出现但每一次都要让人理解它的含义而不是复制粘贴。5.2 C程序连接MySQL的编译链接要点不是所有项目都是Java。C接MySQL也是老牌需求很多工具软件、桌面客户端都靠它连库。C连接MySQL主要用官方提供的mysql.h接口Linux环境上需要安装开发包一般叫libmysqlclient-dev或mysql-community-devel。最简单的连接代码骨架#include mysql.h #include stdio.h int main() { MYSQL *conn mysql_init(NULL); if (conn NULL) { fprintf(stderr, 初始化失败\n); return -1; } if (mysql_real_connect(conn, 127.0.0.1, user, password, shop, 3306, NULL, 0) NULL) { fprintf(stderr, 连接失败: %s\n, mysql_error(conn)); mysql_close(conn); return -1; } mysql_query(conn, SELECT id, username FROM user LIMIT 10); MYSQL_RES *res mysql_store_result(conn); MYSQL_ROW row; while ((row mysql_fetch_row(res)) ! NULL) { printf(%s %s\n, row[0], row[1]); } mysql_free_result(res); mysql_close(conn); return 0; }编译时注意三个点头文件路径、库文件路径、链接库名g -o demo demo.cpp -lmysqlclient -I/usr/include/mysql如果连接后中文乱码要在mysql_real_connect之后执行mysql_set_character_set(conn, utf8mb4);。C程序里很多“连接失败”其实是网络不通或者防火墙没放开3306端口别一股脑怪MySQL。5.3 连接池到底是什么HikariCP / Druid参数怎么配新手第一次写JavaWeb完整项目时通常会在DAO层用DriverManager.getConnection()直接连数据库。这么做功能是没问题但性能很差。因为每次建立数据库连接都要走网络握手、认证耗时往往在百毫秒量级用户一多连接一开一关就吃亏。连接池的原理很简单程序启动时提前创建一批数据库连接放在池子里用的时候取出一个用完了放回去。它解决的是“连接复用”不是“把连接变快”。Spring Boot时代最常用的是HikariCP配置核心参数spring: datasource: url: jdbc:mysql://127.0.0.1:3306/shop?... username: dev password: xxx hikari: maximum-pool-size: 10 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000老一点的JavaWeb项目里Druid也很常见参数叫法不太一样initialSize2 maxActive20 minIdle2 maxWait60000 validationQuerySELECT 1maximum-pool-size不是越大越好。连接数过高数据库本身的线程调度、锁竞争都会变严重。一个常见的经验值是普通业务4核8G的机器上MySQL最大连接数200-300单应用连接池给10-20就够别一上来就设个100。5.4 Navicat、DBeaver、Workbench的选择以及离线驱动下载第一次会习惯下载Navicat但网上搜“Navicat破解”的搜索结果很危险里面带的激活工具十有八九有问题。我的看法是能用官方免费工具的就别碰破解版。官方MySQL Workbench是免费且持续维护的DBeaver社区版也很强都支持Windows、Linux和macOS。DBeaver连MySQL时也常会遇到一个离线环境问题默认驱动管理器会从网上下载驱动jar包。公司内网没有外网权限下载会一直卡住这时候就需要“离线驱动”。做法是从官网或网友的仓库里找到对应版本的mysql-connector-java.jar然后打开DBeaver的“数据库 - 驱动管理器 - MySQL”编辑驱动库把你的本地jar文件加进去重启即可。DBeaver里连接MySQL 8时如果报“Public Key Retrieval is not allowed”就在连接设置的“驱动属性”里把allowPublicKeyRetrieval改成true。这个思路跟JDBC连接串完全一样。理解了这层逻辑不管换什么客户端你都难不住。5.5 大数据组件连不上MySQL的常见症状现在做数据开发的人早晚要遇到Sqoop、Kettle、Flink这些组件去连MySQL。最典型的就是Sqoop导入报错症状全是连接超时、认证失败、驱动类找不到。sqoop连接MySQL有一个很隐蔽的坑驱动jar包放错位置。Sqoop官方目录只加载lib目录下的驱动你需要把mysql-connector-java.jar复制到$SQOOP_HOME/lib下并且版本要和MySQL匹配。低版本的Java驱动连接MySQL 8时会因为SSL握手失败直接报Exception: SSL connection error。解决方式同样是useSSLfalse或者直接升级驱动到8.x。另一个症状是Access denied for user xxxip。这多半是MySQL的用户授权问题。MySQL授权是按“用户来源IP”区分的不要以为你是所有主机都能访问。建用户时要显式指定CREATE USER dataworker% IDENTIFIED BY 密码; GRANT ALL PRIVILEGES ON *.* TO dataworker%;如果只需要业务库权限别直接给*.*按实际库名授权更安全。6. 上了线才知道的坑慢查询、SQL超时和主键设计6.1 执行SQL超时先看锁等待再看网络第一次在生产环境执行一条UPDATE等了半天没反应最后超时。很多人的第一反应是网络不好或者调整SQL语句但真正原因大部分时候是锁等待。一条正常的更新语句被另一个事务阻塞会话状态会显示Waiting for lock。这种时候光优化自己这端SQL没用要把阻塞别人事务的连接找出来杀掉。排查命令三件套SHOW PROCESSLIST;这个命令能看到所有数据库会话重点看Time列和State列比如Waiting for table metadata lock说明有DDL在等表结构锁。SELECT * FROM performance_schema.data_lock_waits\G这个可以看谁在等谁的锁。SHOW ENGINE INNODB STATUS;最近一次死锁信息基本都在这里包括事务持有的锁、等着的锁和对应的SQL。我们项目第一次出这个问题是一个后台定时任务开启了事务处理过程中抛了异常但没有ROLLBACK事务一直没关闭导致整个表更新全部堵住。所以另一个习惯也非常重要应用里开启事务后一定要写try-finally或者try-with-resources哪怕出错也要保证ROLLBACK执行。6.2 性能调优EXPLAIN与慢查询日志第一次观察MySQL性能问题我不建议一上来就堆各种配置参数先开慢查询日志让数据库自己告诉你哪些SQL慢。SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;这样设置之后超过1秒的SQL会记录到慢日志文件。分析时可以用mysqldumpslow工具mysqldumpslow /var/log/mysql/slow.log慢查询日志能暴露很多“表面没问题但实际低效”的SQL。我见过最典型的一个案例列表页查询用户订单因为WHERE条件里对索引字段做了函数处理导致索引失效。比如在created_at上写WHERE DATE(created_at) 2024-01-01函数会让优化器放弃索引改成WHERE created_at 2024-01-01 AND created_at 2024-01-02就恢复索引了。还要学会看EXPLAIN的type列ALL最差是全表扫描index表示把索引全部扫了一遍range是范围扫描还不错ref和const是高效的等值命中。优化方向就是让慢SQL尽量从ALL进化到range或ref。6.3 字段类型、默认值和int5的小坑MySQL是弱类型数据库这既是方便也是坑。新人写SQL时经常写出类似SELECT age 5 FROM user;这在MySQL里就是普通的数值计算age列的每个值加5。如果你数据里age被存成了字符串18也没问题MySQL会隐式转成数字。但一旦字符串不是纯数字比如18aMySQL会转出前导数字18a18就转成0。这个隐式转换的规则不熟写出来的结果可能就是错的排查起来极其难受。字段默认值0也是一个典型案例。很多人把某个字段设成NOT NULL DEFAULT 0想着“没值就填0”这没问题。但如果你用ALTER TABLE把一个已有非空数据的列改成NOT NULL DEFAULT 0MySQL可能需要重建表耗时很长。而且如果表里之前有NULL值ALTER还可能要给你一个“非法默认值”的报错因为严格模式下把NULL转成DEFAULT 0并不是MySQL能自动决定的行为。所以改表之前先查一下现有数据SELECT COUNT(*) FROM user WHERE age IS NULL;6.4 上线前后的常用巡检命令第一次把项目部署到服务器之前最好把下面这些命令挨个执行一遍给自己吃个定心丸。-- 看版本和字符集 SELECT VERSION(); SHOW VARIABLES LIKE character_set_server; -- 看当前连接数确认连接池没有把连接数打满 SHOW STATUS LIKE Threads_connected; SHOW VARIABLES LIKE max_connections; -- 看慢查询是否开启 SHOW VARIABLES LIKE slow_query_log; -- 看当前所有会话排查异常连接 SHOW PROCESSLIST;还有一个每天都要做的事就是备份。第一次做备份我推荐直接用mysqldump简单可靠mysqldump -uroot -p --single-transaction shop shop_backup.sql--single-transaction是基于InnoDB的一致性快照备份备份过程中不会锁死业务写入。这个参数很关键我见过有人备份时不加它结果备份开始后所有写操作全部被阻塞被同事骂了一早上。如果你做的是JavaWeb项目上线前还应该确认应用层连接池的maxActive或者maximum-pool-size小于MySQL的max_connections否则一旦应用连接数涨上来数据库会被连接打爆。排查一下就一条命令的事却能在上线高峰期救你一命。第一次使用MySQL的经历本质上是“一边抄、一边踩、一边懂”的过程。安装也好建表也好遇到报错也罢关键不是死记命令而是理解背后那套关于数据存储、连接、索引和事务的模型。把这套模型折腾明白了以后无论换成RDS还是云数据库你都能很快适应。如果你正在经历这个阶段记住一个原则每次动手前先备份每次改完表先看影响行数每次出了锁问题先看SHOW PROCESSLIST这三条能帮你挡住大部分生产事故。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表