news 2026/9/18 23:04:00

MySQL命令行基本操作全攻略:从连接到优化实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL命令行基本操作全攻略:从连接到优化实战

干这行这么多年,MySQL基本操作命令几乎天天要敲。不管是在开发环境建个库表、帮同事排查一个连接不上的尴尬问题,还是线上环境查一条慢SQL,最后都得落到那几条命令上。经常有新人问我,MySQL到底该怎么入门?我的回答一直很简单:别急着上可视化工具和框架,先把命令行下那套基本操作玩明白,后面所有优化、排错、架构相关的技能才有地基。这篇文章我就把自己日常用得最频繁的MySQL命令整理出来,从连接登录、建表改表、增删改查,到查询优化、存储过程和问题排查,按实战场景走一遍,希望能帮你少踩几个坑。

1. 连接MySQL:命令行登录与最基础的库表查看命令

1.1 登录命令与初始密码处理

连接MySQL最常用的就是mysql这个客户端命令,基本格式是这样的:

mysql -h127.0.0.1 -P3306 -uroot -p

参数含义很直白:-h指定主机地址,-P指定端口,-u指定用户,-p表示需要输入密码。如果是在MySQL服务器本机登录,可以直接省略-h参数,走默认的socket连接,速度更快:

mysql -uroot -p

这里有个很多新手第一次就卡住的问题,就是MySQL安装完以后,初始密码到底在哪?MySQL 8.0在初始化安装时,会生成一个临时密码,这个密码通常会写到错误日志里。Linux下可以这样找:

grep "temporary password" /var/log/mysqld.log

Windows下则在MySQL数据目录下的*.err文件里搜。拿到临时密码登录后,MySQL会要求你先改密码,否则什么都干不了。改密码的命令如下:

ALTER USER 'root'@'localhost' IDENTIFIED BY '新的强密码';

这里强调一下,如果你装的是MySQL 8.0,默认密码插件是caching_sha2_password,密码复杂度要求也比较高,至少得包含大写、小写、数字和特殊字符。曾经我见过不少同事一上来就想设个123456,结果直接被策略拒了,还以为是自己操作有问题。

1.2 库表查看与字符集检查

登录MySQL之后,先养成一个好习惯:确认自己在哪个库,表结构是什么样。最基础的一组查看命令如下:

SHOW DATABASES; USE your_db; SHOW TABLES; DESC your_table; SHOW CREATE TABLE your_table\G

SHOW DATABASES列出所有数据库,USE切换当前库,SHOW TABLES查看库下所有表,DESC查看表字段信息,SHOW CREATE TABLE则能看到建表语句的完整定义。我强烈建议你在排查表结构问题时用最后一条,因为DESC只显示字段名、类型、默认值这些基础信息,而SHOW CREATE TABLE能看到索引、约束、字符集、自增值等全量细节,还可以直接复制出来改一版新表。

字符集问题也是新手重灾区。登录后先看几个变量:

SHOW VARIABLES LIKE 'character_set%';

如果发现character_set_server不是utf8mb4,建议在配置文件里固定成utf8mb4。现在的新表基本无脑用utf8mb4,它能覆盖emoji和生僻字,兼容性最好。曾经有次线上插入一条带emoji昵称的数据,直接报错,查了半天才发现库表字符集还是老旧的utf8mb3,改成utf8mb4后问题消失,这种细节在文本、评论类业务里特别常见。

2. DDL操作:建表、改表、删表的基本命令与选型细节

2.1 建表语句:字段类型、主键与自增

DDL是Data Definition Language,建表、改表、删表都归它管。一张表的建表语句写得好不好,直接决定了后面查询快不快、扩展顺不顺。我常用的建表模板大概长这样:

CREATE TABLE `user` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', `username` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '用户名', `age` INT NOT NULL DEFAULT 0 COMMENT '年龄', `balance` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '余额', `status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1正常 0禁用', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`), KEY `idx_age` (`age`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';

在字段类型选择上,几个建议供参考:整型主键优先BIGINT而不是INT,避免单表数据量大以后自增主键溢出;金额字段一定要用DECIMAL,不能图省事用FLOAT或DOUBLE,否则算钱算到分的时候会出误差;状态类字段用TINYINT,比字符串省空间,也方便扩展;时间字段建议用DATETIME,范围足够日常使用,TIMESTAMP到2038年会有溢出风险。

默认值也是建表时容易忽略的点。热搜里经常出现“mysql设置默认值为0”,其实就是字段定义里的DEFAULT 0。对于数字、字符串、时间这类字段,尽量都设上默认值,能避免不少因为插入数据时漏了字段导致的NULL问题。特别提醒一句:TEXT/BLOB类型在MySQL里不能有默认值,如果你真需要给大文本字段一个“默认空字符串”,要么用VARCHAR,要么在业务层处理。

2.2 修改表结构:ALTER TABLE和索引管理

上线需求经常要加字段、加索引,最常用的就是ALTER TABLE。加字段的语法:

ALTER TABLE `user` ADD COLUMN `nickname` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '昵称' AFTER `username`;

AFTER关键字可以控制新字段加在哪个字段后面,不加的话默认加到最后一列。修改字段类型或默认值,用MODIFY

ALTER TABLE `user` MODIFY COLUMN `age` INT NOT NULL DEFAULT 18 COMMENT '年龄';

改字段名用CHANGE

ALTER TABLE `user` CHANGE COLUMN `nickname` `nick_name` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '昵称';

注意,CHANGE后面要写两遍字段名,先旧后新,很多新手容易漏。删字段用DROP COLUMN,这个操作要谨慎,列数据会一并删掉且不可恢复。

索引操作也走ALTER,或者用独立的CREATE/DROP INDEX:

ALTER TABLE `user` ADD INDEX `idx_username_age` (`username`, `age`); CREATE INDEX `idx_age` ON `user` (`age`); ALTER TABLE `user` DROP INDEX `idx_age`; DROP INDEX `idx_age` ON `user`;

MySQL创建索引的命令不难,难在索引怎么设计。一个经验之谈:联合索引要遵循最左前缀原则,查询条件里如果没有联合索引的最左字段,索引基本用不上。比如建立(username, age)联合索引后,WHERE age = 20就享受不到这个索引的优化,但WHERE username = 'xx'可以。

2.3 DROP、TRUNCATE、DELETE到底有啥区别

这三个命令都能让数据消失,但行为完全不同,我用一个表格把核心差异列出来:

操作能否带WHERE是否触发触发器是否重置自增能否回滚
DELETE可以不会可以
TRUNCATE不可以不会不可以
DROP不可以不会表都没了不可以

DELETE是逐行删除,走事务,可以配合WHERE精准删数据,删错还能ROLLBACK救回来。TRUNCATE会把整张表清空并重置自增ID,速度非常快,但它是隐式提交,一旦执行就没有回旋余地。DROP更彻底,直接把表结构和数据全部干掉。

我在实际工作中有一条死规矩:生产环境上,DROPTRUNCATE必须经过确认再加锁或备份;DELETE必须带WHERE,不带WHERE的DELETE相当于自毁。如果要清空一张表但保留表结构,多数情况下TRUNCATE比DELETE快得多,但前提是你要能接受自增ID被重置。

3. 数据操作:INSERT、UPDATE、DELETE的进阶用法与坑

3.1 INSERT插入:单行、多行与INSERT SELECT

INSERT是写入数据的根本方式,最基础的写法:

INSERT INTO `user` (`username`, `age`, `balance`) VALUES ('zhangsan', 25, 100.00);

一次插入多行时,可以在VALUES后面跟多组括号,中间用逗号分隔:

INSERT INTO `user` (`username`, `age`, `balance`) VALUES ('lisi', 26, 200.00), ('wangwu', 27, 300.00);

批量插入比一条条INSERT快得多,这背后是减少客户端和服务端交互次数的原理。如果要从另一张表搬运数据,可以用INSERT ... SELECT:

INSERT INTO `user_backup` (`username`, `age`, `balance`) SELECT `username`, `age`, `balance` FROM `user` WHERE `age` > 30;

这里有个容易踩的坑:SELECT出来的字段类型、长度、顺序必须和目标表能对得上,否则会报Data too long或者字段数量不匹配。另外,如果目标表有唯一索引,批量插入时遇到重复键会整条语句报错,MySQL提供了一个很实用的语法INSERT ... ON DUPLICATE KEY UPDATE

INSERT INTO `user` (`username`, `age`) VALUES ('zhangsan', 30) ON DUPLICATE KEY UPDATE `age` = VALUES(`age`);

意思是如果唯一索引冲突,就改成更新。这个语法在同步数据、幂等写入场景里非常好用,能少写一大段判断逻辑。

3.2 UPDATE更新语法与子查询冲突

UPDATE的基本语法:

UPDATE `user` SET `age` = 26 WHERE `username` = 'zhangsan';

支持同时更新多个字段,用逗号分隔。也支持多表关联更新:

UPDATE `user` u JOIN `user_order` o ON u.`id` = o.`user_id` SET u.`balance` = u.`balance` - o.`amount` WHERE o.`status` = 1;

这里JOIN的用法很实用,等于把另一张表的计算条件拿到UPDATE语句里一起执行。但MySQL里有个著名限制:UPDATE时不能在同一语句中直接查询并修改同一张表。比如下面这个写法会直接报错You can't specify target table 'user' for update in FROM clause

UPDATE `user` SET `status` = 1 WHERE `id` IN (SELECT `id` FROM `user` WHERE `age` < 18);

解决方式也很经典,把子查询再包一层派生表:

UPDATE `user` SET `status` = 1 WHERE `id` IN ( SELECT `id` FROM ( SELECT `id` FROM `user` WHERE `age` < 18 ) AS tmp );

热搜词“mysql中更新子查询”指的就是这个场景。原理是MySQL不允许对目标表进行子查询时直接做修改,套一层临时表就能绕开限制。还有一个细节:UPDATE语句里如果WHERE走了主键或唯一索引,影响行数通常是1,否则可能影响多行,修改前最好先确认条件范围。严格养成习惯的话,线上更新大批量数据,最好分批次LIMIT更新,减少锁范围和主从延迟。

3.3 DELETE删除的安全操作习惯

DELETE语法本身不复杂:

DELETE FROM `user` WHERE `id` = 100;

但删除操作是生产事故高发区。最常见的问题就是忘了带WHERE,或者WHERE写得不对,把不该删的数据删了。我的做法是:写DELETE之前,先把同样的WHERE条件放到SELECT里查一遍,确认影响的数据量符合预期,再换成DELETE执行。比如:

SELECT `id` FROM `user` WHERE `age` < 10; DELETE FROM `user` WHERE `age` < 10;

如果数据量特别大,比如一次要删几百万行,直接DELETE会把大量行锁住,还可能拖垮主从复制。更稳妥的办法是分批删除:

DELETE FROM `user` WHERE `age` < 10 LIMIT 1000;

循环执行这个语句,直到影响行数为0。这种操作方式虽然慢,但对线上业务最友好。要清空整张表又不需要回滚时,TRUNCATE比DELETE快很多,它能直接释放表空间而不是一点点删行。

4. SELECT查询:排序、连接、分组与执行计划

4.1 ORDER BY排序与LIMIT分页

查询是MySQL使用频率最高的操作,先看排序。ORDER BY支持一个或多个字段,还能指定升降序:

SELECT `username`, `age` FROM `user` ORDER BY `age` DESC, `id` ASC LIMIT 20;

这个语句的含义是:优先按age降序排,age相同再按id升序排。注意,如果你对多个字段排序,每个字段后面的DESC/ASC都要写清楚,不写默认ASC。

分页通常配合LIMIT使用:

SELECT * FROM `user` ORDER BY `id` LIMIT 0, 20; SELECT * FROM `user` ORDER BY `id` LIMIT 20 OFFSET 0;

两条写法等价,LIMIT后面第一个参数是偏移量,第二个是返回条数。但这里要提醒一个深分页性能问题:当偏移量非常大时,比如LIMIT 200000, 20,MySQL仍然需要扫描并丢弃前200000行,效率很低。我处理这种场景通常会改成基于主键的游标方式:

SELECT * FROM `user` WHERE `id` > 200000 ORDER BY `id` LIMIT 20;

前提是业务允许用上一页的最大id作为下一页的起点,这种方式在百万级数据下也能保持稳定速度。另外,日常开发中我很少用SELECT *,更习惯把需要返回的字段名显式写出来,一是减少不必要的数据传输,二是避免后面表结构加了字段导致返回结果集变化,影响接口兼容性。

4.2 JOIN连接:INNER、LEFT、RIGHT到底怎么选

JOIN是MySQL里最容易搞混的概念。简单说,JOIN就是把两张表按某个条件横向拼接起来。INNER JOIN只返回两表都匹配得上的行;LEFT JOIN返回左表全部行,右表没有匹配就补NULL;RIGHT JOIN反过来,返回右表全部行,左表无匹配补NULL。

SELECT u.`username`, o.`order_no` FROM `user` u INNER JOIN `user_order` o ON u.`id` = o.`user_id`; SELECT u.`username`, o.`order_no` FROM `user` u LEFT JOIN `user_order` o ON u.`id` = o.`user_id`;

第一句查出来的是所有下过单的用户和他们的订单号,没下过单的用户不会出现;第二句查出来的是所有用户以及订单号,没下过单的用户order_no会是NULL。我个人的经验是:RIGHT JOIN用得很少,因为只要把表的顺序调换一下,RIGHT JOIN的效果就能用LEFT JOIN实现,统一用LEFT JOIN反而更不容易出错。

JOIN时还有一个不容忽视的点:ON和WHERE的过滤时机不同。LEFT JOIN中,写在ON里的条件只影响右表匹配,而写在WHERE里的条件会在左表保留逻辑之前参与过滤,结果可能完全不同。如果你发现LEFT JOIN结果中左表行数少了,多半是本来想放在ON里的条件被放进了WHERE。

4.3 GROUP BY与HAVING的实践细节

GROUP BY的作用是把相同字段值的行合并成一组,通常配合聚合函数使用,比如COUNT、SUM、AVG、MAX、MIN:

SELECT `status`, COUNT(*) AS `cnt` FROM `user` GROUP BY `status`;

这句话就是按状态分组,统计每个状态下的用户总数。如果还要对聚合后的结果做过滤,要用HAVING而不是WHERE:

SELECT `status`, COUNT(*) AS `cnt` FROM `user` GROUP BY `status` HAVING `cnt` > 10;

WHERE是在分组之前对原始行进行过滤,HAVING是在分组之后对聚合结果进行过滤,这个区别必须记牢。

另一个高频坑是ONLY_FULL_GROUP_BY模式。MySQL 5.7之后默认开启了sql_mode中的ONLY_FULL_GROUP_BY,意味着SELECT后面只能出现GROUP BY里的字段,以及聚合函数。如果查了不在GROUP BY里的字段,MySQL会直接报错。比如下面这句在开启该模式后会报错:

SELECT `username`, `age` FROM `user` GROUP BY `status`;

因为username和age既不在GROUP BY里,也不是聚合结果。这种写法的本意可能是想取每组里的某一行,但在MySQL里并不安全,需要改成子查询或窗口函数实现。另外,GROUP BY字段如果走了索引,速度会快很多,这提醒我们在设计高频分组查询时,尽量让分组字段成为索引的一部分。

4.4 用EXPLAIN看执行计划

凡是我写的SELECT语句,如果在测试环境或者线上有性能问题,第一件事就是看执行计划:

EXPLAIN SELECT u.`username`, o.`order_no` FROM `user` u LEFT JOIN `user_order` o ON u.`id` = o.`user_id` WHERE u.`age` > 20;

执行计划返回一张结果表,关键字段就这么几个:type表示访问类型,从好到差大致是systemconsteq_refrefrangeindexALLALL就是全表扫描,通常是性能瓶颈。key表示实际用到的索引,rows是MySQL估算的需要扫描的行数,Extra里如果出现Using filesortUsing temporary,说明排序或分组没有用到索引,需要重点优化。

看懂执行计划后,很多慢查询的原因就清楚了:要么没建索引,要么索引建了但没被选中,要么因为函数、隐式类型转换导致索引失效。比如对索引字段使用WHERE DATE(create_time) = '2024-01-01',索引大概率失效,应该写成范围查询create_time >= '2024-01-01' AND create_time < '2024-01-02'。这类细节光背命令没用,只能实际跑EXPLAIN多对比。

5. 事务、存储过程与运维高频命令

5.1 事务控制命令与隔离级别

MySQL的InnoDB引擎支持事务,事务能让一组操作要么全部成功、要么全部回滚。最常用的事务控制命令就三个:

START TRANSACTION; UPDATE `account` SET `balance` = `balance` - 100 WHERE `id` = 1; UPDATE `account` SET `balance` = `balance` + 100 WHERE `id` = 2; COMMIT;

当两条UPDATE都执行成功后,COMMIT才会提交;如果中间某一步失败,执行ROLLBACK:

ROLLBACK;

就可以把这两条UPDATE的影响全部撤销。这个“要么全做,要么全不做”的特性就是原子性。事务还有一致性、隔离性、持久性,合起来叫ACID。隔离性靠的是隔离级别控制,MySQL默认是REPEATABLE READ(可重复读),它保证同一个事务里多次读同一行数据结果一致。除了默认级别,还有READ UNCOMMITTED、READ COMMITTED、SERIALIZABLE。

关于MVCC(多版本并发控制),它是InnoDB隔离级别的核心机制。简单说,每一行数据在更新时都会保留旧版本的快照,事务读取时通过版本链和Read View来判定能看到哪个版本,从而实现读写不互相阻塞。这也是为什么在REPEATABLE READ下,一个事务里多次SELECT能看到一致快照的原因。这部分理解起来有点抽象,但不用着急,先在行为层面记住“读写不阻塞”这个特性就行。

5.2 存储过程的声明、变量与调用

存储过程就是一段预先编译好的SQL逻辑,适合封装复杂、重复的业务操作。声明一个最简单的存储过程:

DELIMITER // CREATE PROCEDURE `get_user_count`(IN `p_age` INT, OUT `p_count` INT) BEGIN SELECT COUNT(*) INTO `p_count` FROM `user` WHERE `age` > `p_age`; END // DELIMITER ;

这里DELIMITER //的作用是把语句分隔符临时改成//,因为存储过程内部有多条SQL,默认的;会提前结束语句。写完再改回;。调用方式:

CALL `get_user_count`(18, @cnt); SELECT @cnt;

IN参数是传入值,OUT参数是输出值,INOUT参数既能传进也能传出。查询结果通过SELECT ... INTO赋给输出变量。删除存储过程用DROP PROCEDURE IF EXISTS get_user_count;

存储过程在金融对账、定时统计这类场景还有一定价值,但说实话,现在大部分团队把复杂逻辑放在应用层处理,存储过程用得越来越少了。我建议新手把它当作理解MySQL编程能力的窗口,但不要事事都往存储过程上套,因为调试和维护成本确实比应用代码高不少。

5.3 运维必备:processlist、status、variables

日常运维排查问题时,有几个命令比任何可视化工具都直接。当数据库卡顿、有查询长时间不返回时,第一时间看当前连接都在干什么:

SHOW FULL PROCESSLIST;

这个命令会列出所有连接ID、用户、库、命令类型、执行时间和SQL内容。如果发现某个连接长时间处于Sleep状态,又或者某条UPDATE执行了几千秒,基本可以定位到问题来源。锁死时还可以强制杀掉某个连接:

KILL 12345;

看MySQL当前的运行状态指标,用SHOW STATUS:

SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW GLOBAL STATUS LIKE 'QPS';

前者看当前连接数,后者看每秒查询数。连接数突然飙升,通常要检查是不是有慢查询堆积或者连接池配置不合理。需要看配置参数时,用SHOW VARIABLES:

SHOW VARIABLES LIKE '%max_connections%'; SHOW VARIABLES LIKE '%timeout%';

查看表的索引信息,用:

SHOW INDEX FROM `user`;

排查空间占用情况,information_schema系统库里可以直接查:

SELECT `table_name`, `table_rows` FROM `information_schema`.`tables` WHERE `table_schema` = 'your_db' ORDER BY `table_rows` DESC;

这些命令单看都不复杂,但组合起来就是一套完整的数据库体检流程:先看进程、再看状态、然后定位慢SQL和执行计划。

6. 常见问题排查:安装、连接与版本兼容

6.1 安装后的初始密码和端口问题

MySQL安装配置教程里最常被问到的就是初始密码和端口。前面提过,MySQL 8.0的临时密码会写到错误日志里,Linux下路径一般是/var/log/mysqld.log。如果翻遍日志都没找到临时密码,还有一个备用方案:在配置文件里临时加一行skip-grant-tables,重启MySQL后可以免密登录,然后手动重置密码。操作过程大致如下:

# 编辑 /etc/my.cnf,在 [mysqld] 下加 skip-grant-tables # 重启服务 systemctl restart mysqld # 免密登录 mysql -uroot # 重置密码 FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';

改完以后一定要把配置文件里的skip-grant-tables注释或删掉,再重启服务。这个方法能救命,但也非常危险,因为只要它是开启状态,任何本机进程都可以免密登录数据库,所以不能在生产环境长期开着。

端口问题也很典型。默认端口3306,如果启动时报错或者外网连不上,先检查端口是否被占用:

netstat -tlnp | grep 3306

如果被别的进程占用了,要么改MySQL的port配置,要么处理占用进程。云服务器上还要注意安全组是否放通了3306端口,这是我遇到过好多次的“MySQL配置完全没问题但远程就是连不上”的原因。

6.2 Navicat、Workbench连接不上怎么办

用Navicat或MySQL Workbench连接MySQL,报错原因五花八门,但排查思路比较固定。Navicat连接不上时,按顺序检查这几个点:

  1. MySQL服务是否启动:systemctl status mysqldservice mysql status
  2. 端口是否可达:在客户端机器上执行telnet 服务器IP 3306,不通就要检查防火墙和安全组。
  3. 用户主机权限:MySQL的用户由“用户名+主机”共同构成,比如root@'localhost'就只能在本地登录。如果要允许远程,需要设置root@'%'或者专门建一个远程用户:
CREATE USER 'app'@'%' IDENTIFIED BY '密码'; GRANT ALL PRIVILEGES ON `your_db`.* TO 'app'@'%'; FLUSH PRIVILEGES;
  1. 密码插件兼容性:MySQL 8.0默认用caching_sha2_password,比较老版本的Navicat或驱动可能不支持,表现是连接时直接报错。解决办法是把用户的插件改成mysql_native_password:
ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY '密码';

MySQL Workbench的使用教程里,核心就是填入主机、端口、用户名、密码,测试连接成功后就能进入图形界面执行SQL、管理表结构和数据导出。它和Navicat的区别主要是跨平台和定位,Workbench官方免费,Navicat功能更丰富,按个人习惯选就行。

6.3 驱动版本与框架报错怎么定位

版本兼容问题在Java、Python项目里特别常见。比如Django项目启动时如果报django.db.utils.NotSupportedError: MySQL 8.4 or later is required (found 8.0),这个报错通常不是要求你必须装MySQL 8.4,而是Django版本检查逻辑认为当前MySQL版本不满足要求。解决思路有两种:其一,如果MySQL是8.0的长期支持版本,就把Django版本降级到与MySQL 8.0兼容的版本;其二,如果是新版Django确实要求更新的MySQL版本,那就得升级数据库或换个兼容的驱动。这里核心思路是:先看报错来自哪个依赖库,再根据依赖库的官方支持矩阵调整版本,别盲目升级或降级。

另一个常见场景是Sqoop连接不上MySQL。Sqoop是数据迁移工具,连不上时重点检查JDBC驱动JAR包是否放在正确目录、连接串格式是否正确、MySQL用户是否允许从Sqoop所在主机访问。连接串里还要显式加参数控制编码和SSL,比如:

jdbc:mysql://192.168.1.100:3306/your_db?useSSL=false&characterEncoding=utf8

如果是用Docker安装MySQL,还要注意容器端口映射和数据持久化。简单示例:

docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=yourpass \ -e MYSQL_ROOT_HOST=% \ -v mysql_data:/var/lib/mysql \ mysql:8.0

MYSQL_ROOT_HOST=%很关键,没有它,root默认只允许容器内访问,宿主机和外部工具都连不上。数据目录挂载到宿主机卷上,则能避免容器删除后数据全丢。

最后分享一个我个人的工作习惯:不管操作哪个环境的数据库,只要涉及UPDATE或DELETE,我都会先把WHERE条件放进SELECT里跑一遍,确认影响行数和数据内容符合预期,再回头执行修改语句。这个过程多花不了几秒钟,但能在关键时刻避免删错数据、改错数据的事故。另外,把常用的MySQL命令整理成属于自己的速查表,遇到问题直接查,比硬记可靠得多。MySQL的基本操作命令就这么多,但每一条背后都藏着不少细节,真正用过、踩过坑,才算真正掌握。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 23:02:55

WeWe RSS:把公众号变成 RSS 订阅源,5 分钟私有部署全记录

WeWe RSS&#xff1a;把公众号变成 RSS 订阅源&#xff0c;5 分钟私有部署全记录 【免费下载链接】wewe-rss &#x1f917;更优雅的微信公众号订阅方式&#xff0c;支持私有化部署、微信公众号RSS生成&#xff08;基于微信读书&#xff09; 项目地址: https://gitcode.com/Gi…

作者头像 李华
网站建设 2026/9/18 23:02:11

OpenClaw 配 TaoToken:文件整理、写代码、做报表,只需一套 Key

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 23:01:33

BERT文本分类在经济研究中的应用:论文复现全流程实战

先说明一下&#xff0c;我这边没有找到金星晔等&#xff08;2024&#xff09;《经济研究》这篇论文的原文全文&#xff0c;但你给的标题信息已经足够定位到这是哪一类工作&#xff1a;用BERT这类预训练语言模型做经济学文本分类&#xff0c;而且作者团队把整个流程&#xff08;…

作者头像 李华
网站建设 2026/9/18 23:01:07

MATLAB车牌识别系统设计:从HSV形态学到模板匹配的完整实现

简介&#xff1a;MATLAB车牌识别系统实现毕业论文&#xff0c;围绕车牌识别全流程展开&#xff0c;涵盖图像预处理、车牌定位、字符分割与识别等关键环节&#xff0c;从系统架构到算法选择均有详细说明&#xff0c;并对比了不同方法的适用范围与MATLAB平台的优势和局限。压缩包…

作者头像 李华