Skip to content

Commit 548b002

Browse files
committed
Add additional information about MySQL character sets
1 parent 5c01ecd commit 548b002

File tree

1 file changed

+158
-5
lines changed

1 file changed

+158
-5
lines changed

docs/database/character-set.md

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,160 @@ UTF-32 的规则最简单,不过缺陷也比较明显,对于英文字母这
102102

103103
MySQL 支持很多种字符编码的方式,比如 UTF-8、GB2312、GBK、BIG5。
104104

105-
你可以通过 `SHOW CHARSET` 命令来查看。
105+
### 查看支持的字符集
106+
107+
你可以通过 `SHOW CHARSET` 命令来查看,支持like和where子句。
106108

107109
![](https://oss.javaguide.cn/javaguide/image-20211008164229671.png)
108110

111+
### 默认字符集
112+
113+
在MySQL5.7中,默认字符集是 `latin1` ;在MySQL8.0中,默认字符集是 `utf8mb4`
114+
115+
### 字符集的层次级别
116+
117+
MySQL中的字符集有以下的层次级别:
118+
119+
* `server`
120+
* `database`
121+
* `table`
122+
* `column`
123+
124+
它们的优先级可以简单的认为是从上往下依次增大,也即 `column` 的优先级会大于 `table` 等其余层次的
125+
126+
#### server
127+
128+
不同版本的MySQL其 `server` 级别的字符集默认值不同,在MySQL5.7中,其默认值是 `latin1` ;在MySQL8.0中,其默认值是 `utf8mb4`
129+
130+
当然也可以通过在启动 `mysqld` 时指定 `--character-set-server` 来设置 `server` 级别的字符集。或者如果你是通过源码构建的方式启动的MySQL,你可以在 `cmake` 命令中指定选项:
131+
132+
```sh
133+
cmake . -DDEFAULT_CHARSET=latin1
134+
```
135+
136+
此外,你也可以在运行时改变 ` character_set_server` 的值,从而达到修改 `server` 级别的字符集的目的。
137+
138+
`server` 级别的字符集可以在我们使用 `create database` 语句未指定字符集时被用作默认值,同时它还可能会对连接字符集产生影响,这个可以查看 **[`MySQL Connector/J 8.0` 文档](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-charsets.html)**
139+
140+
#### database
141+
142+
`database` 级别的字符集是我们在创建数据库和修改数据库时指定的:
143+
144+
```sql
145+
CREATE DATABASE db_name
146+
[[DEFAULT] CHARACTER SET charset_name]
147+
[[DEFAULT] COLLATE collation_name]
148+
149+
ALTER DATABASE db_name
150+
[[DEFAULT] CHARACTER SET charset_name]
151+
[[DEFAULT] COLLATE collation_name]
152+
```
153+
154+
如前面所说,如果在执行上述语句时未指定字符集,那么MySQL将会使用 `server` 级别的字符集。这里关于字符是如何选择的,还有一些比较细致的规则,建议自己翻阅MySQL文档。
155+
156+
可以通过下面的方式查看某个数据库的字符集:
157+
158+
```sql
159+
USE db_name;
160+
SELECT @@character_set_database, @@collation_database;
161+
```
162+
163+
```sql
164+
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
165+
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name';
166+
```
167+
168+
#### table
169+
170+
`table` 级别的字符集是在创建表和修改表时指定的:
171+
172+
```sql
173+
CREATE TABLE tbl_name (column_list)
174+
[[DEFAULT] CHARACTER SET charset_name]
175+
[COLLATE collation_name]]
176+
177+
ALTER TABLE tbl_name
178+
[[DEFAULT] CHARACTER SET charset_name]
179+
[COLLATE collation_name]
180+
```
181+
182+
如果在创建表和修改表时未指定字符集,那么将会使用 `database` 级别的字符集。这里关于字符是如何选择的,还有一些比较细致的规则,建议自己翻阅MySQL文档。
183+
184+
#### column
185+
186+
`column` 级别的字符集同样是在创建表和修改表时指定的,只不过它是定义在列中。下面是个例子:
187+
188+
```sql
189+
CREATE TABLE t1
190+
(
191+
col1 VARCHAR(5)
192+
CHARACTER SET latin1
193+
COLLATE latin1_german1_ci
194+
);
195+
```
196+
197+
如果未指定列级别的字符集,那么将会使用表级别的字符集。这里关于字符是如何选择的,还有一些比较细致的规则,建议自己翻阅MySQL文档。
198+
199+
### 连接字符集
200+
201+
前面说到了字符集的层次级别,它们是和存储相关的。而连接字符集涉及的是和MySQL服务器的通信。
202+
203+
连接字符集与下面这几个变量息息相关:
204+
205+
* `character_set_client` (描述了客户端发送给服务器的SQL语句使用的是什么字符集)
206+
* `character_set_connection` (描述了服务器接收到SQL语句时使用什么字符集进行翻译)
207+
* `character_set_results` (描述了服务器返回给客户端的结果使用的是什么字符集)
208+
209+
它们的值可以通过下面的SQL语句查询:
210+
211+
```sql
212+
SELECT * FROM performance_schema.session_variables
213+
WHERE VARIABLE_NAME IN (
214+
'character_set_client', 'character_set_connection',
215+
'character_set_results', 'collation_connection'
216+
) ORDER BY VARIABLE_NAME;
217+
```
218+
219+
```sql
220+
SHOW SESSION VARIABLES LIKE 'character\_set\_%';
221+
```
222+
223+
如果要想修改前面提到的几个变量的值,有以下方式:
224+
225+
* 修改配置文件
226+
227+
比如加上:
228+
229+
```
230+
[mysql]
231+
# 只针对MySQL客户端程序
232+
default-character-set=utf8mb4
233+
```
234+
235+
* 使用SQL语句
236+
237+
比如:
238+
239+
```sql
240+
set names utf8mb4
241+
# 或者一个个进行修改
242+
# SET character_set_client = utf8mb4;
243+
# SET character_set_results = utf8mb4;
244+
# SET collation_connection = utf8mb4;
245+
```
246+
247+
### jdbc对连接字符集的影响
248+
249+
不知道你们有没有碰到过存储emoji表情正常,但是使用类似Navicat之类的软件的进行查询的时候,发现emoji表情变成了问号的情况。这个问题很有可能就是jdbc驱动引起的。
250+
251+
根据前面的内容,我们知道连接字符集也是会影响我们存储的数据的,而jdbc驱动会影响连接字符集。
252+
253+
`DataGrip 2023.1.2` 来说,在它配置数据源的高级对话框中,可以看到 `characterSetResults` 的默认值是 `utf8` ,在使用 `jdbc driver 8.0.25` 时,连接字符集最后会被设置成 `utf8mb3` 。那么这种情况下emoji表情就会被显示为问号,并且当前版本驱动还不支持把 `characterSetResults` 设置为 `utf8mb4` ,不过换成 `jdbc driver 8.0.29` 却是允许的。
254+
255+
具体可以看一下StackOverflow的**[这个回答](https://stackoverflow.com/questions/54815419/datagrip-mysql-stores-emojis-correctly-but-displays-them-as/76625399#76625399)**
256+
257+
### UTF-8使用
258+
109259
通常情况下,我们建议使用 UTF-8 作为默认的字符编码方式。
110260

111261
不过,这里有一个小坑。
@@ -127,10 +277,10 @@ MySQL 字符编码集中有两套 UTF-8 编码实现:
127277

128278
```sql
129279
CREATE TABLE `user` (
130-
`id` varchar(66) CHARACTER SET utf8mb4 NOT NULL,
131-
`name` varchar(33) CHARACTER SET utf8mb4 NOT NULL,
132-
`phone` varchar(33) CHARACTER SET utf8mb4 DEFAULT NULL,
133-
`password` varchar(100) CHARACTER SET utf8mb4 DEFAULT NULL
280+
`id` varchar(66) CHARACTER SET utf8mb3 NOT NULL,
281+
`name` varchar(33) CHARACTER SET utf8mb3 NOT NULL,
282+
`phone` varchar(33) CHARACTER SET utf8mb3 DEFAULT NULL,
283+
`password` varchar(100) CHARACTER SET utf8mb3 DEFAULT NULL
134284
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
135285
```
136286

@@ -157,3 +307,6 @@ Incorrect string value: '\xF0\x9F\x98\x98\xF0\x9F...' for column 'name' at row 1
157307
- GB2312-维基百科:<https://zh.wikipedia.org/wiki/GB_2312>
158308
- UTF-8-维基百科:<https://zh.wikipedia.org/wiki/UTF-8>
159309
- GB18030-维基百科: <https://zh.wikipedia.org/wiki/GB_18030>
310+
- MySQL8文档:<https://dev.mysql.com/doc/refman/8.0/en/charset.html>
311+
- MySQL5.7文档:<https://dev.mysql.com/doc/refman/5.7/en/charset.html>
312+
- MySQL Connector/J文档:<https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-charsets.html>

0 commit comments

Comments
 (0)