从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • 计算机历史

  • 数字电路

  • 计算机组成原理

  • 汇编语言

  • C语言

  • 数据结构

  • 操作系统

  • Linux

  • 计算机网络

  • Git

  • 数据库

  • 计算机小知识

    • 简单聊聊计算机之中的时间
    • 简单聊聊字符编码
    • ASCII字符表和说明
    • ASCII的SOH的用处
    • 回车和换行
    • 汉字是怎么编码的
    • 简单聊聊Unicode
    • 手持两把锟斤拷,口中疾呼烫烫烫
    • 数据库与编码
      • 编码的重要性
      • 演示
      • 小结
      • 参考
    • 编程语言与字符编码
    • URL编码
    • Base64编码
    • 字符编码小结
    • literacy
  • 编译原理

  • 名人堂

  • 计算机基础
  • 计算机小知识
2022-12-21
目录

数据库与编码

# 19.数据库与编码

‍

以MySQL为例。在MySQL中,utf8编码并不是真正意义上的utf8,而是utf8mb3。utf8mb3支持的字符集是0~65535之间的BMP的字符,最多支持3个字节,一些生僻字和emoji是不支持。

这会导致什么问题呢?如果你数据库使用的是utf8mb3编码,那么在insert一些4字节的字符的时候,会报错:

insert into t (name) value('😂')
SQL 错误 [1366] [HY000]: Incorrect string value: '\xF0\x9F\x98\x82' for column 'name' at row 1

insert into t (name) value('𡋾')
SQL 错误 [1366] [HY000]: Incorrect string value: '\xF0\xA1\x88\xBE' for column 'name' at row 1
1
2
3
4
5

‍

‍

​​这个问题被广大开发者发现后,终于在2010年 ,MySQL发布了MySQL5.53,在创建数据库时可以用一个新的字符集utf8mb4,支持4个字节的字符

官方文档醒目的提醒了大家说utf8mb3会在未来的版本中删除,并建议用户优先使用utf8mb4

所以在创建数据库的时候,确保的使用是utf8mb4,而不是utf8mb3。

‍

官方的一些说明:MySQL :: MySQL 8.0 Reference Manual :: 10.9.2 The utf8mb3 Character Set (3-Byte UTF-8 Unicode Encoding) (opens new window)

Applications that use UTF-8 data but require supplementary character support should use utf8mb4​ rather than utf8mb3​ (see Section 10.9.1, “The utf8mb4 Character Set (4-Byte UTF-8 Unicode Encoding)” (opens new window)).

‍

‍

可以通过查看数据库的建表语句来检查:

show create database 数据库名\G;
-- 例如
mysql> show create database dblog\G;
*************************** 1. row ***************************
       Database: dblog
Create Database: CREATE DATABASE `dblog` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */
1 row in set (0.00 sec)
1
2
3
4
5
6
7

笔者在MySQL 8.0.27下尝试了下,默认都是用的utf8mb4编码了,而在很久之前,默认编码是utf8mb3.

如果是早期的数据库表,有需求要兼容4个字节的字符的话,可以修改对应的字段的编码或数据库的编码。

​​

# 编码的重要性

编码是一件非常重要的事情。现代很多系统都要求支持Unicode。如果不支持,有什么后果呢?

举个例子,如果某个人名字带有生僻字,银行的系统不支持,那么这个客户就不能去该银行做业务,直接损失了一名客户。

‍

例如:在有没有谁的朋友名字中含有“䶮”字的? - 知乎 (opens new window)里有人提到:

本人有两张储蓄卡,招商和工商,招商的户名是某䶮,工商银行的户名是某(YAN3),亲身经历证明:招商储蓄卡无法变更为公积金联名卡,主要原因是姓名不一致,因此肯定没有办法提取公积金

‍

一个名字叫“䶮”的人的苦恼:开不了银行账户,用不了微信、支付宝 (opens new window)

近日,多位人士向记者表示,自己的名字中含有 “䶮”等汉字,在办理公积金、银行卡、第三方支付、手机卡等金融、通信业务时,名字无法被验证,导致业务无法办理。

甚至,因为没法申请银行账户,微信、支付宝也拒绝使用,有的银行建议名字带有“䶮”字的用户改回繁体字“龑”。

生僻字带来金融交易中的麻烦,这一情况并不鲜见。

‍

# 演示

实践出真知,我们来演示下,本文是在Windows下的MySQL 5演示。

首先创建一个数据库,并指定字符集

mysql> create database testunicode default character set utf8 collate utf8_general_ci;
Query OK, 1 row affected (0.00 sec)
1
2

‍

创建完后,可以检查下该数据库的编码

mysql> show create database testunicode;
+------------+--------------------------------------------------------+
| Database    | Create Database                                                      |
+------------+--------------------------------------------------------+
| testunicode | CREATE DATABASE `testunicode` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+-------------+--------------------------------------------------------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7

‍

使用该数据库并创建表,可以看到该表的默认编码是UTF8

mysql> use testunicode;
Database changed

mysql> create table t (name varchar(50));
Query OK, 0 rows affected (0.25 sec)

mysql> show create table t
CREATE TABLE `t` (
  `name` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1
2
3
4
5
6
7
8
9
10

‍

尝试insert一个emoji,确实有报错:

insert into t (name) value('😂')

SQL 错误 [1366] [HY000]: Incorrect string value: '\xF0\x9F\x98\x82' for column 'name' at row 1
1
2
3

‍

接下来我们尝试更换字符集,并创建一个新表:

mysql> ALTER DATABASE `testunicode`
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_bin;

mysql> create table tu (name varchar(50))

mysql> show create table t
CREATE TABLE `t` (
  `name` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1
2
3
4
5
6
7
8
9
10

‍

尝试重新insert,结果是能成功insert。

mysql> insert into tu (name) value('😂')
1

# 小结

虽然目前MySQL默认都是使用utf8mb4了,但一些早期的项目还是使用的utf8mb3,希望读者们如果遇到了该编码问题能有思路,知道是怎么回事、怎么修复。

触类旁通,其他关系型数据库,例如Oracle等,也需要考虑编码问题

‍

# 参考

英文版(需科学上网)In MySQL, never use “utf8”. Use “utf8mb4”. | by Adam Hooper | Medium (opens new window)

中文版:记住,永远不要在MySQL中使用“utf8”_数据库_Adam Hooper_InfoQ精选文章 (opens new window)

一个名字叫“䶮”的人的苦恼:开不了银行账户,用不了微信、支付宝 (opens new window)

曝光 MySQL 的 一个坑,不要再使用 UTF-8 了? (opens new window)

‍

在GitHub上编辑此页 (opens new window)
上次更新: 2023/9/5 18:15:55
手持两把锟斤拷,口中疾呼烫烫烫
编程语言与字符编码

← 手持两把锟斤拷,口中疾呼烫烫烫 编程语言与字符编码→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式