尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Ubuntu 24.04安装MySQL 8并配置utf8mb4解决中文乱码完整指南

Ubuntu 24.04安装MySQL 8并配置utf8mb4解决中文乱码完整指南 做AI课程的数据库模块身边好几个朋友都被同一个问题折腾过MySQL装好了、表建好了、Python代码也连上了结果往库里写中文变成一列问号存个emoji直接报错。最后查来查去基本都是字符集没配置到位。这个坑在Ubuntu 24.04.3 LTS上装MySQL 8同样存在所以我把这套完整的安装和utf8mb4配置过程整理出来给后面做AI课程、NLP数据处理的人一个可以直接照搬的流程少走一段弯路。这篇文章主要解决三件事怎么在Ubuntu 24.04.3 LTS上装好MySQL 8怎么把服务器端、客户端、建库建表三个层面的字符集统一到utf8mb4以及配置完之后怎么验证、遇到乱码怎么排查。适合正在搭AI课程环境的学生、自己练手做数据项目的开发者还有带数据库模块的课程设计者参考。1. 为什么数据库模块要先解决字符集1.1 一次中文乱码演示引发的连锁反应我最早接触这个坑是在帮一个项目组搭数据环境的时候。项目组做了一个中文情感分析的小Demo从网上抓了一批评论数据清洗完要存进MySQL。开发的同学跑了一段很简单的INSERT语句屏幕上干干净净query ok但等SELECT出来一看中文全变成了“???”Python读出来直接UnicodeDecodeError。当时第一反应是Python连接字符串没写对折腾了半天编码参数还是一样。后来用mysql命令行客户端直接插一条中文发现同样是问号这才意识到问题出在MySQL服务端而不是业务代码。这个经历在AI课程里太常见了。做文本分类、情感分析、对话系统免不了要跟中文、标点、特殊符号打交道。如果数据库在源头就把字符集限制住了后面所有数据清洗、特征工程、模型训练到的数据都是坏的方向全反。国产系统和软件生态里中文乱码是个老话题但很多新入门的人仍然会踩。尤其是MySQL 8虽然默认字符集已经从latin1改成了utf8mb4但实际操作中受系统环境变量、客户端工具默认值、旧配置文件影响字符集仍然可能被悄悄改回去。1.2 utf8mb4和utf8到底差在哪MySQL里的utf8字符集一个字符最多占3个字节这导致它只能覆盖基本多语言平面BMP里的字符。中文常用字基本在BMP范围内所以一个三字节的“测”字没问题。但emoji表情、部分生僻汉字、某些注音符号都是超出BMP的一个字符需要4个字节。MySQL早期把utf8上限做成3字节更多是历史包袱跟Unicode标准后来扩展的情况不匹配。utf8mb4才是真正意义上支持完整Unicode的变长编码一个字符最多4字节向下完全兼容utf8存中文、英文、emoji都不在话下。所以配置目标很明确把服务端默认字符集、客户端连接字符集、数据库和表的字符集全部统一到utf8mb4。宁可写库的时候多占一两个字节也比将来数据乱码、项目返工划算得多。2. 动手之前确认系统状态和软件源2.1 三分钟检查Ubuntu版本和基础环境在Ubuntu 24.04.3 LTS上装MySQL之前先花三分钟确认一下系统状态省得装到一半发现环境不干净。打开终端依次执行下面几条命令。lsb_release -a uname -m df -h / free -hlsb_release -a用来确认系统确实是我们预期的版本比如输出里出现Ubuntu 24.04.3 LTS。uname -m看架构绝大多数服务器和PC都是x86_64如果是ARM架构的机器软件仓库会自动匹配arm64的包安装流程一样。df -h和free -h则是看磁盘和内存MySQL 8安装后大概占几百MB数据目录另算至少留出几个G余量内存有个2G以上跑测试环境就比较稳了。这一步不是走形式。我见过有人在没看磁盘空间的情况下直接apt安装结果下载到一半把根目录塞满整个系统卡到无法操作最后只能重启进恢复模式清理。提前看一眼真的就三分钟。2.2 该不该先跑sudo apt updateUbuntu的软件源里默认就有mysql-server 8.0的包不需要额外添加第三方源。装之前先更新索引sudo apt update这一步很多教程会跳过但我不建议省。apt update会把软件源里的包列表同步到本地确保后面装到的是源里最新的8.0.x版本。如果长时间没更新apt可能解析到一个过期的版本号或者因为依赖版本对不上而报错。更新完索引之后顺便看一眼有没有需要升级的包。不需要刻意做全量升级只要确认mysql相关的包不在损坏状态就行。直接进入安装环节。3. 安装MySQL 8命令不多细节不少3.1 一条apt命令装完但别急着登录在Ubuntu 24.04.3 LTS上安装MySQL 8非常简单只需要一条命令。sudo apt install mysql-server -y-y表示自动确认安装过程中的所有提示省得装到一半还要再按一次回车。安装过程会拉取mysql-server、mysql-client、mysql-common这些关联包整个过程一两分钟具体速度看网络状况。装完之后有一个很容易忽略的点Ubuntu仓库里的mysql-server包不会在安装完成后自动弹一个“设置root密码”的交互界面。很多从Windows和CentOS转过来的人会习惯性用mysql -uroot -p去登录结果看到提示要密码随便输入一个就报Access denied然后就懵了。Ubuntu下MySQL 8的root账号默认用的是auth_socket认证插件换句话说就是本地系统root用户通过socket方式登录时不需要密码。所以安装完成后正确的登录方式是sudo mysql直接进到MySQL命令行不需要任何密码。这一步跟很多人脑子里的“MySQL必须设密码才能进去”不一样理解了认证机制就不会卡住。3.2 确认服务状态和安装版本登录成功后第一件事是看版本。SELECT VERSION();一般会输出类似8.0.40-0ubuntu0.24.04.1这样的版本号。看到8开头就是我们要的MySQL 8确认无误。然后退出MySQL回到Shell里检查一下服务状态。sudo systemctl status mysql输出中Active状态如果显示active (running)说明服务正常。如果没有显示running用sudo systemctl start mysql手动启动再让服务开机自启sudo systemctl enable mysqlenable这一步让MySQL在系统重启后自动拉起。开发机上忘了设置也没多大问题但服务器上漏了这一步哪天机房断电重启数据库起不来业务全部瘫痪那就不划算了。安装阶段还有个细节值得说Ubuntu会自动把MySQL服务启动同时创建好默认的datadir也就是/var/lib/mysql目录。不需要手动去初始化数据目录apt安装已经全部做了。如果你去找旧版教程里面那些mysqld --initialize之类的步骤在Ubuntu 24.04上是不需要的照着老教程跑反而可能把现有data目录搞乱。4. mysql_secure_installation的安全配置4.1 交互式配置每一步该怎么选MySQL装好后第一件正经事不是急着建库而是跑安全初始化脚本把默认的匿名用户、测试库这些隐患清掉。sudo mysql_secure_installation这个脚本是交互式的一步一步按提示来。每一步的选择我按实际经验整理一下。第一步一般会问要不要装密码强度校验组件Validate Password Component。这是一个密码复杂度检查插件开启后会强制密码必须满足某种强度。建议按Y它能有效防止把密码设成123456这种水平。不想装也没关系按N跳过后面自己设定密码时注意长度和复杂度就行。接着是设置root用户的密码。这里要注意在Ubuntu上root走的是auth_socket认证设置密码只是把auth_socket之外的另一条密码认证路径配出来。用sudo mysql进入依然不需要密码但如果后续用TCP/IP和root账号连接就需要这个密码。开发环境建议把密码设成一个不容易忘记但又有复杂度的字符串。后面几个问题基本都是按YRemove anonymous users?移除匿名用户选YDisallow root login remotely?禁止root远程登录选YRemove test database and access to it?删除test数据库选YReload privilege tables now?刷新权限表选Y跑完这个脚本一个最小可用的安全基线就立起来了。4.2 root账号的认证方式Ubuntu与CentOS的差异设置密码的过程中很多人会撞上同一个困惑为什么我已经mysql_secure_installation里设了密码用mysql -uroot -p还是进不去用sudo mysql却能进去这就要回到Ubuntu特有的auth_socket认证了。MySQL的用户认证不是只有密码一种而是可以指定认证插件。Ubuntu软件包把root配成了auth_socket它在验证时只检查发起连接的用户是不是操作系统的root用户完全不看密码。所以在Ubuntu上维护MySQL日常管理用sudo mysql就够了。如果你更习惯用密码登录想给root切换成caching_sha2_password认证可以登录后执行ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY 你的密码; FLUSH PRIVILEGES;执行完之后root在本地就能用密码登录了。但要注意一旦改成密码认证sudo mysql这种免密方式就失效了因为auth_socket被换掉了。两种方式选一种别来回切来回切容易把自己锁在门外。这个认证差异是Ubuntu用户最容易困惑的点。不像CentOS默认root就是密码认证Ubuntu默认走socket如果不懂这点可能卡在这个看似简单的地方很久。5. utf8mb4的三层配置服务端、连接层、建库建表5.1 服务端全局配置怎么写MySQL 8虽然默认字符集是utf8mb4但为了显式确认、也为了防止某些客户端或特殊情况把全局值改掉推荐在配置文件里写死。MySQL在Ubuntu上的主配置文件是/etc/mysql/my.cnf但它会通过include的方式加载/etc/mysql/mysql.conf.d/目录下的所有文件。真正的mysqld配置写在mysqld.cnf里。sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf在[mysqld]段的合适位置加两行character-set-server utf8mb4 collation-server utf8mb4_unicode_cicharacter-set-server指定服务端字符集collation-server指定排序规则。排序规则我这里选的是utf8mb4_unicode_ci它是通用Unicode排序规则兼容性和稳定性都比较好。保存退出后重启MySQL让配置生效。sudo systemctl restart mysql重启后登录执行下面这条SQL确认服务端字符集已经改过来。SHOW VARIABLES WHERE Variable_name IN (character_set_server, collation_server);两个值如果分别是utf8mb4和utf8mb4_unicode_ci服务端这层就到位了。5.2 连接层字符集为什么是另一回事服务端配置好只完成了一半。客户端连上来的时候MySQL会为每个会话单独设置一组字符集变量character_set_client、character_set_connection、character_set_results。这三个变量决定客户端发过来的SQL和文本怎么解析、怎么转换。MySQL 8里这组变量的默认值往往能对上utf8mb4但不保证所有工具都如此。尤其是一些老版本的图形化客户端、或者通过ODBC/JDBC连接的程序可能会在握手阶段传一个不同的字符集。为了从根上锁定连接层可以单独给mysql客户端设置默认字符集。在/etc/mysql/conf.d/下新建一个文件比如mysql_client.cnf写入[mysql] default-character-set utf8mb4更通用的做法是在全局my.cnf里增加[client]段[client] default-character-set utf8mb4这样不仅mysql命令行生效很多基于libmysqlclient的程序也能拿到这个默认值。改完后重新登录MySQL再看连接层变量SHOW VARIABLES LIKE character\_set\_connection; SHOW VARIABLES LIKE character\_set\_client;connection和client如果都是utf8mb4说明程序连接的时候不再需要用SET NAMES utf8mb4手工指定了。Python的pymysql连接是另一条常见链路驱动不读Linux的my.cnf客户端配置所以连接参数里必须显式加上charset。import pymysql conn pymysql.connect( host127.0.0.1, port3306, userdemo_user, password你的密码, databaseai_course, charsetutf8mb4 )这里的关键点在于服务端配置解决的是“数据存进去是什么编码”客户端参数解决的是“程序读出来和传进去时是什么编码”。两个都对上才不会出现命令行看着正常、程序一跑就乱码的灵异事件。5.3 新库新表与旧库旧表的字符集迁移即使全局配置是utf8mb4创建的数据库如果不显式指定字符集也会继承全局变量正常来说就是utf8mb4。但更稳妥的做法是建库时显式写明CREATE DATABASE IF NOT EXISTS ai_course DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;建表时同样显式声明CREATE TABLE IF NOT EXISTS user_text ( id INT AUTO_INCREMENT PRIMARY KEY, content TEXT CHARACTER SET utf8mb4, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;显式声明的好处是就算后来有人把服务器全局配置改回了latin1已有的库表字符集也已经是独立的、不会被动摇。如果库和表已经建好而且里面存了数据迁移字符集就要小心了。数据库层级的修改很简单ALTER DATABASE ai_course CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;但表层级需要更谨慎因为表字符集不会跟着数据库自动变数据迁移需要重写整个表。用下面的命令ALTER TABLE user_text CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;CONVERT TO不仅会改表默认字符集还会把每一列的数据类型、字符集都转换一遍等于把整张表重写一次。数据量大时这个过程会锁表并占用不少IO生产环境要避开业务高峰期操作先做备份再执行。如果只需要改某个字段不重写全表可以用MODIFYALTER TABLE user_text MODIFY content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;这两个命令有本质区别。数据量小无所谓数据量大到几百G时选错命令代价差别很大。6. 验证配置不要只看不测6.1 用SQL直接确认全局变量配置写完了不能光看配置文件里写了什么就认为生效了。必须进到MySQL里亲眼确认实际运行的值。先跑一组最全的检查SHOW VARIABLES LIKE character\_set\_%; SHOW VARIABLES LIKE collation\_%;输出结果里重点确认这几个变量的值全部是utf8mb4或utf8mb4_unicode_cicharacter_set_servercharacter_set_databasecharacter_set_clientcharacter_set_connectioncharacter_set_resultscollation_servercollation_database如果发现character_set_database还是latin1说明你连接的数据库本身是在旧配置下创建的需要回到5.3节去做库级迁移。再检查具体的库和表SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME ai_course;SELECT TABLE_NAME, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA ai_course;通过information_schema查出来的信息比SHOW CREATE TABLE更直观一张表一行不用逐张翻。6.2 实际写入中文和emoji的验收测试变量全对不代表端到端就一定通最好做一次真实的读写验证。进入ai_course库建一张临时测试表插入包含中文和emoji的内容。CREATE TABLE charset_test (content TEXT) DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; INSERT INTO charset_test (content) VALUES (中文文本测试); INSERT INTO charset_test (content) VALUES (English and emoji: ); SELECT * FROM charset_test;如果两条记录都能正确读出来显示的不是问号、不是乱码中文和emoji都完好无损说明整条链路的字符集配置成功了。再测一组更极端的情况把Python读写也跑一遍。pymysql连接配置好charsetutf8mb4后插入同样的内容再读出来两边对比一致才说明业务代码阶段没有问题。测试完把临时表删掉DROP TABLE charset_test;这一步验证的是从客户端到服务端再到存储的完整通路只查变量不看实际数据很容易漏掉客户端配置没生效的情况。7. 踩坑记录从报错到乱码的排查链路7.1 重启MySQL后配置不生效先查这三点配置了utf8mb4之后重启MySQL执行SHOW VARIABLES LIKE character_set_server发现还是老值这是最典型的坑。我按排查顺序整理了三步。第一配置文件有没有写对位置和段落。character-set-server必须写在[mysqld]段下面如果手滑写到了[client]段mysqld进程根本不会读它。用my_print_defaults mysqld可以查看mysqld实际能读到的有效配置项比人工翻文件更可靠。my_print_defaults mysqld第二改完有没有真的重启成功。systemctl restart mysql有时候会因为配置错误启动失败然后直接回滚到旧状态但又不报任何明显错误。用下面命令确认服务真正起来了。sudo systemctl status mysql journalctl -u mysql | tail -30如果journalctl里有类似“unknown variable”的报错说明配置项写错了仔细核对有没有把character-set-server拼成character-set或者多加了下划线。第三有没有其他配置文件把它覆盖了。Ubuntu的MySQL配置是多个文件include叠加的如果在/etc/mysql/conf.d/某个文件里也有character-set-server后面的文件会覆盖前面的设置。用my_print_defaults mysqld把所有生效配置打出来一眼就能看出最终生效的是哪个文件、哪个值。7.2 命令行正常、程序连上就乱码命令行mysql客户端显示中文、emoji都正常但一到Python、Java或者图形工具就乱码这类问题几乎都出在连接层。先看程序的连接字符串有没有显式指定字符集。pymysql要写charsetutf8mb4JDBC要写characterEncodingutf8mb4。不要依赖MySQL服务端的默认值因为驱动在连接握手阶段有自己的编码协商逻辑。Java的JDBC连接串形如jdbc:mysql://127.0.0.1:3306/ai_course?characterEncodingutf8mb4useUnicodetrueserverTimezoneUTC连接串里的characterEncodingutf8mb4MySQL驱动会把它映射成客户端的utf8mb4编码。如果连接参数已经写了还是乱码检查一下程序和运行环境的locale。Linux下的JVM和Python在某些情况下会读取LANG、LC_ALL环境变量决定默认编码如果系统locale是POSIX或者C输出端可能变成ASCII虽然库里存的还是utf8mb4但读出来打印到终端就乱。启动前设置export LANGC.UTF-8 export LC_ALLC.UTF-8再做一次程序读写的测试。先SET NAMES utf8mb4再执行读写如果这样正常而直接连接就乱基本可以确认是连接层参数没写对。7.3 排序规则的选择unicode_ci还是0900_ai_ciMySQL 8默认的排序规则是utf8mb4_0900_ai_ci基于Unicode 9.0支持重音不敏感和大小写不敏感的排序比较。我前面推荐的是utf8mb4_unicode_ci这两个的实际区别不仔细看很难发现。utf8mb4_0900_ai_ci是MySQL 8引入的现代化排序规则对大多数语言排序都比unicode_ci更准确性能也更好。如果你的数据只在MySQL 8里流转没有跨版本迁移的需求直接用默认的0900_ai_ci没问题。utf8mb4_unicode_ci是通用选择兼容性更好。如果将来要把数据导到MariaDB、或者从老版本MySQL迁过来unicode_ci的兼容风险更小。这两个排序规则都支持中文排序也都不影响存储能力只影响比较和ORDER BY的行为。选哪个都不耽误干活。怕选择困难的话就用MySQL 8默认的utf8mb4_0900_ai_ci这也是官方推荐。我上面写unicode_ci是出于习惯实际部署中换成0900_ai_ci完全没问题只要库、表、列三个层级的排序规则保持一致就行。AI课程里最烦人的其实是另一个隐藏点如果业务代码里用Python排序中文而数据库用的是MySQL的排序规则两边排序结果可能不一致。但这个属于应用层和存储层的分工问题不是字符集配置能解决的。在课程设计上建议把排序需求集中在同一层实现不要让两边互相依赖。8. 配置完成后的收尾验证清单最后整理一份我自己每次装完都会过一遍的检查清单照着做一遍就能确定整个环境没有漏项。服务状态sudo systemctl status mysql确认activerunning登录方式sudo mysql能进或用密码认证的方式能进服务端变量character_set_server和collation_server都是utf8mb4连接层变量character_set_client、character_set_connection、character_set_results都是utf8mb4新建数据库显式指定DEFAULT CHARACTER SET utf8mb4新建表显式指定DEFAULT CHARSETutf8mb4实际读写插入中文和emojiSELECT能原样读出来程序连接pymysql或JDBC等实际跑一遍增删改查这个清单看起来简单但每一项我都见过有人漏掉。尤其第7步很多人配置完字符集只用SELECT 中文测一下感觉没问题就收工了结果后来程序里插入emoji直接报“Incorrect string value”又要回头排查。把完整链路测一遍比查一百个变量的值都有效。配置MySQL的utf8mb4不是背命令而是要理解一件事字符集在MySQL里有服务端、连接层、数据库和表三个独立层面任何一层不统一整条链路都会出问题。Ubuntu的apt安装方式又带来了root认证方式的特殊性跟网上很多CentOS教程不一样。把这几个点串起来理解不管是AI课程的数据模块还是别的业务项目遇到同类环境都不会再被卡住。最后分享一个我自己的操作习惯所有配置文件改完不会立刻去跑业务而是先保存一个副本包含完整的配置内容和当时的验证结果。出了新问题回看配置副本就能快速定位是不是改配置引起的比临时回忆、猜来猜去高效得多。数据库环境这东西越到后面越费时间在排障上前期把每一步都留下记录后面能省下大把时间。
返回列表