报错详情
使用的命令和遇到的报错如下:
mysql> insert TestTable(ID, Name, Gender, HireDate) values('2021001', '赵凯峰', '男', '2021-01-01'); ERROR 1366 (HY000): Incorrect string value: '\xE8\xB5\xB5\xE5\x87\xAF...' for column 'Name' at row 1
注:
- 本文中使用数据库名称为
TestBase
; - 本文中使用的数据表名称为
TestTable
和TestTable2
.
报错分析
“Incorrect string value” 的意思就是“字符串值错误”,一般情况下,这样的报错意味着数据库中的编码存在问题。
可以使用如下命令查看数据库当前的编码方式:
show create database TestBase;
回显结果如下:
+----------+-------------------------------------------------------------------+ | Database | Create Database | +----------+-------------------------------------------------------------------+ | TestBase | CREATE DATABASE `TestBase` /*!40100 DEFAULT CHARACTER SET latin1 */ | +----------+-------------------------------------------------------------------+ 1 row in set (0.00 sec)
从 DEFAULT CHARACTER SET latin1
可知,数据库当前默认的编码格式为 latin1
. 从名称可以猜测,latin1
编码是一种主要用于拉丁(Latin)语系文字和符号的编码方案,事实上,latin1
码除了向下兼容专用于拉丁语系字母和符号的 ASCII 码之外,还能表示西欧语言、希腊语、泰语、阿拉伯语和希伯来语中出现的字母和符号——也就是说,latin1
码是无法解码中文字符的,如果让 MySQL 以默认的 latin1
编码格式处理包含中文的内容就会导致上述报错。
解决方案一
修改已存在的数据库编码格式为 UTF-8:
alter database TestBase character set utf8;
解决方案二
在创建数据库的时候指定编码格式为 UTF-8:
create database TestBase character set utf8;
解决方案三
在 MySQL 中,我们可以为数据库、数据表和数据列分别设置编码格式,而且,在指定了编码格式的情况下,数据列的编码格式优先于数据表,数据表的编码格式优先于数据列;在没有指定编码格式的情况下,数据列继承数据表的编码格式,数据表继承数据库的编码格式——但是继承是以时序为前提的,例如,数据表继承的是在创建该表前数据库的编码格式,在一个数据表已经存在的情况下,修改该数据表所在数据库的编码格式并不会导致该数据表原有编码格式的改变。
比如,我们先创建一个使用默认的 latin1
编码格式的数据库:
mysql> create database TestBase; Query OK, 1 row affected (0.00 sec) mysql> show create database TestBase; +----------+---------------------------------------------------------------------+ | Database | Create Database | +----------+---------------------------------------------------------------------+ | TestBase | CREATE DATABASE `TestBase` /*!40100 DEFAULT CHARACTER SET latin1 */ | +----------+---------------------------------------------------------------------+ 1 row in set (0.00 sec)
接着,在不指定编码格式的情况下创建一个包含 Name
数据列的数据表(由前述可知,此时该数据表的编码格式为 latin1
):
mysql> use TestBase; Database changed mysql> create table TestTable1 -> ( -> Name varchar(20) -> ); Query OK, 0 rows affected (0.07 sec)
然后,尝试在 Name
数据列中插入包含中文的数据,发现会报错,插入全英文的数据就不会报错:
mysql> insert TestTable1 (Name) values ('荒原之梦网'); ERROR 1366 (HY000): Incorrect string value: '\xE8\x8D\x92\xE5\x8E\x9F...' for column 'Name' at row 1 mysql> insert TestTable1 (Name) values ('zhaokaifeng.com'); Query OK, 1 row affected (0.01 sec)
同样还是在 TestTable1
这个表里面,我们新增加一个名为 NickName
的数据列,同时使用 character set utf8
设定该数据列使用 UTF-8 编码:
mysql> alter table TestTable1 add column NickName varchar(20) character set utf8 after Name; Query OK, 0 rows affected (0.04 sec) Records: 0 Duplicates: 0 Warnings: 0
之后,在 TestTable1
表下面的 NickName
数据列下插入包含中文的数据,显示可以正常插入:
mysql> insert TestTable1 (NickName) values ('小原和小梦'); Query OK, 1 row affected (0.03 sec)
接着,在 TestTable1
表下面的 Name
数据列下插入包含中文的数据,显示不可以正常插入,这说明我们刚才的编码设定只对 NickName
数据列有效,即便 NickName
数据列和 Nmae
数据列都在同一个数据表里面也互不干扰:
mysql> insert TestTable1 (Name) values ('小原和小梦'); ERROR 1366 (HY000): Incorrect string value: '\xE5\xB0\x8F\xE5\x8E\x9F...' for column 'Name' at row 1
我们还可以在创建数据表的时候为其指定默认的编码格式,例如,我们在编码格式为 latin1
的 TestBase
的数据库中创建一个名为 TestTable2
的数据表,该表的默认编码设定为 UTF-8. 同时,在 TestTable2
数据表中创建两个数据列,分别是不指定编码的 Name2
数据列和指定编码格式为 latin1
的 NickName
数据列:
l> create table TestTable2 -> ( -> Name2 varchar(20), -> NickName2 varchar(20) character set latin1 -> )default charset=utf8; Query OK, 0 rows affected (0.02 sec)
之后,我们在 Name2
数据列中插入中文,发现可以正常插入,说明未指定编码格式的数据列继承了为数据表指定的 UTF-8 编码格式:
mysql> insert TestTable2 (Name2) values ('荒原之梦网'); Query OK, 1 row affected (0.00 sec)
而当我们在 NickName
数据列中尝试插入中文时,发现不可以正常插入,这说明数据列指定的编码格式的优先级高于数据表的编码格式:
mysql> insert TestTable2 (NickName2) values ('小原和小梦'); ERROR 1366 (HY000): Incorrect string value: '\xE5\xB0\x8F\xE5\x8E\x9F...' for column 'NickName2' at row 1
最后,我们再来查看一下数据库 TestBase
的编码格式,发现其编码格式仍然是 latin1
, 这说明,我们对数据表和数据列编码格式的设定并没有影响到数据库的编码格式:
mysql> show create database TestBase; +----------+---------------------------------------------------------------------+ | Database | Create Database | +----------+---------------------------------------------------------------------+ | TestBase | CREATE DATABASE `TestBase` /*!40100 DEFAULT CHARACTER SET latin1 */ | +----------+---------------------------------------------------------------------+ 1 row in set (0.00 sec)