← 全部文章 运维踩坑

上位机写数据库中文乱码

2022 年 7 月 18 日 · 2 分钟读完

目录
  1. MySQL:C# 读写中文乱码
  2. 乱码可能出在哪
  3. 延伸

项目里遇到的 SQL 中文乱码问题,遇到新的再补充。

MySQL:C# 读写中文乱码

读取:表的列名是中文,用 C# 读出来,除了 ID 其他列名都是乱码:

写入:插入的字符串里有中文,运行就报错:

解决:连接字符串里加上字符集设置:

Server=127.0.0.1;Database=mydb;User ID=root;Password=******;SslMode=none;Charset=utf8mb4

加上后读取和写入都正常了:

原文写的是 charset=utf8。MySQL 里的 utf8 其实是个残缺版本,每个字符最多 3 字节,存不了 emoji 和一部分生僻字;完整的 UTF-8 在 MySQL 里叫 utf8mb4。新项目一律用 utf8mb4。

乱码可能出在哪

一个中文字符从程序到数据库再回来,要经过好几个环节,任何一个环节的编码对不上都会乱:

  1. 表和列的字符集:建表时用的字符集。MySQL 5.7 默认是 latin1,根本存不了中文,插入时就会报错或变成 ???。
  2. 连接的字符集:客户端和服务器之间传输用什么编码。不指定时,Connector/NET 用服务器的默认设置,可能和表的字符集不一样。上面的问题就出在这里。
  3. 程序里的字符串:C# 的 string 是 UTF-16,驱动会按连接字符集转换,这一层一般不会出错。
  4. 查看工具的显示:Navicat、命令行窗口自己的显示编码不对时,数据本身是好的,只是看起来乱码。

排查时可以执行:

SHOW VARIABLES LIKE 'character_set%';   -- 服务器和连接的各项字符集
SHOW CREATE TABLE mytable;              -- 表和列的字符集

一劳永逸的配置:my.ini 里设定服务器默认字符集,之后新建的库和表都是它:

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

已经建好的表要单独转换:ALTER TABLE mytable CONVERT TO CHARACTER SET utf8mb4;(数据多时很慢,先备份)。

延伸

  • 用参数化查询,别拼 SQL 字符串:原文是把中文直接拼进 SQL 语句,除了编码问题,还会有 SQL 注入和引号转义的问题。用参数:
var cmd = new MySqlCommand("INSERT INTO log(msg, time) VALUES(@msg, @time)", conn);
cmd.Parameters.AddWithValue("@msg", "设备启动");
cmd.Parameters.AddWithValue("@time", DateTime.Now);
cmd.ExecuteNonQuery();
  • SQL Server:存中文的列要用 nvarchar 而不是 varchar,写 SQL 字面量时要加 N 前缀:N'设备启动'。用参数化查询就不用管这个。
  • 列名别用中文:能用但麻烦,换个工具、换个驱动就可能出问题。列名用英文,界面上的中文标题在程序里映射。
  • 编码原理:见 字符编码:ASCII、GBK 与 Unicode;源代码文件本身的乱码见 VS 里中文乱码;MySQL 安装和配置文件见 MySQL:安装时启动超时。

# MySQL # 数据库 # 字符编码

原文首发于 blog.csdn.net