• 中文
    • English
  • 注册
  • 查看作者
  • 关于MySQL中ERROR 1366 (HY000): Incorrect string value: ‘\xD3\xA2\xB4\xE7\xB1\xCA..错误的解决方法

    一.  前言

    本文详解记录了该错误产生的原因以及解决的过程,如果您只是为了快速解决本问题,请直接点击目录中的第六节

    二.  数据准备

    我们以5-1节的记录为例,首先创建一个数据库imooc:

    CREATE DATABASE imooc;
     
    USE imooc;

    然后创建一个数据表:

    CREATE TABLE IF NOT EXISTS tdb_goods(
        goods_id    SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
        goods_name  VARCHAR(150) NOT NULL,
        goods_cate  VARCHAR(40)  NOT NULL,
        brand_name  VARCHAR(40)  NOT NULL,
        goods_price DECIMAL(15,3) UNSIGNED NOT NULL DEFAULT 0,
        is_show     BOOLEAN NOT NULL DEFAULT 1,
        is_saleoff  BOOLEAN NOT NULL DEFAULT 0
      );

    三.  插入记录

    我们都知道,MySQL默认的编码为latin1,所以我们上面创建数据表的编码也是latin1:

    mysql> show create table tdb_goods \G
    *************************** 1. row ***************************
           Table: tdb_goods
    Create Table: CREATE TABLE `tdb_goods` (
      `goods_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
      `goods_name` varchar(150) NOT NULL,
      `goods_cate` varchar(40) NOT NULL,
      `brand_name` varchar(40) NOT NULL,
      `goods_price` decimal(15,3) unsigned NOT NULL DEFAULT '0.000',
      `is_show` tinyint(1) NOT NULL DEFAULT '1',
      `is_saleoff` tinyint(1) NOT NULL DEFAULT '0',
      PRIMARY KEY (`goods_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)

    在此基础上,我们插入一条记录:

    INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('R510VC 15.6英寸笔记本','笔记本','华硕','3399',DEFAULT,DEFAULT);

    现在插入记录是可以正常插入的:

    mysql> SELECT * FROM tdb_goods;
    +----------+-----------------------+------------+------------+-------------+---------+------------+
    | goods_id | goods_name            | goods_cate | brand_name | goods_price | is_show | is_saleoff |
    +----------+-----------------------+------------+------------+-------------+---------+------------+
    |        1 | R510VC 15.6英寸笔记本 | 笔记本     | 华硕       |    3399.000 |       1 |          0 |
    +----------+-----------------------+------------+------------+-------------+---------+------------+
    1 row in set (0.00 sec)

    可以看到记录中有中文,很多初学者往往会有疑问,编码为latin1,为什么还支持中文呢?

    其实如果数据库内表的字符集是latin1,那么默认情况下中文也可被支持,latin1覆盖了所有单字节的值,任何其他的码流都可以被看做latin1,如果我们在创建数据库和访问数据库时如果都采用默认的latin1,那就不仅仅支持中文,而是支持任意的编码方式。

    四.  错误产生

    有了上面的基础后,我们来看一下该错误的产生经过:

    我的一个小伙伴在查看我5-1:数据准备后,按照笔记中的要求,创建了数据库,和数据表,并输入了以下指令:

    SET NAMES gbk;

    然后开始插入记录,但是在插入的时候的时候,却出现了1366错误:

    mysql> INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Y400N 14.0英寸笔记本电脑','笔记本','联想','4899',DEFAULT,DEFAULT);
    ERROR 1366 (HY000): Incorrect string value: '\xD3\xA2\xB4\xE7\xB1\xCA...' for column 'goods_name' at row 1

    刚遇到这个问题的时候,我和小伙伴都想到了可能是编码的问题,于是我们首先将my.ini的默认编码修改为utf8,然后正好需要关机,便没有重启MySQL服务,然后修改了数据表的编码:

    ALTER TABLE 表名 DEFAULT CHARACTER SET utf8;

    却发现有三个字段都变成了latin1编码:

    mysql> show create table tdb_goods \G
    *************************** 1. row ***************************
           Table: tdb_goods
    Create Table: CREATE TABLE `tdb_goods` (
      `goods_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
      `goods_name` varchar(150) CHARACTER SET latin1 NOT NULL,
      `goods_cate` varchar(40) CHARACTER SET latin1 NOT NULL,
      `brand_name` varchar(40) CHARACTER SET latin1 NOT NULL,
      `goods_price` decimal(15,3) unsigned NOT NULL DEFAULT '0.000',
      `is_show` tinyint(1) NOT NULL DEFAULT '1',
      `is_saleoff` tinyint(1) NOT NULL DEFAULT '0',
      PRIMARY KEY (`goods_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)

    接着我们又修改字段的编码:

    ALTER TABLE 表名 CHANGE 字段名 字段名 数据类型 CHARACTER SET utf8 NOT NULL;

    发现还是不行……接着又新创建了一个数据库,发现并不是utf8编码,依旧是latin1编码,这时才想起来没有重启MySQL服务,然后重启了MySQL服务(方法请查看1-3:启动与停止MySQL服务)后,发现还是不行,最后只能重新创建了一个数据库,勉强跳过了这个问题

    五.  SET NAMES XXX;

    那么产生该错误的根本原因是什么呢,我们首先来详解一下SET NAMES XXX命令:

    这个命令设置的是客户端发出命令的编码、连接层的编码以及服务端返回结果的编码,相当于是客户端和服务器交互用的编码,而不是数据保存的编码,也就是只影响客户端的显示方式,不影响数据表实际的数据,我们来举例说明:

    首先我们查看一下当前联接系统参数:

    mysql> show variables like 'char%'
        -> ;
    +--------------------------+---------------------------------------------------------+
    | Variable_name            | Value                                                   |
    +--------------------------+---------------------------------------------------------+
    | character_set_client     | latin1                                                  |
    | character_set_connection | latin1                                                  |
    | character_set_database   | latin1                                                  |
    | character_set_filesystem | binary                                                  |
    | character_set_results    | latin1                                                  |
    | character_set_server     | latin1                                                  |
    | character_set_system     | utf8                                                    |
    | character_sets_dir       | C:\Program Files\MySQL\MySQL Server 5.5\share\charsets\ |
    +--------------------------+---------------------------------------------------------+
    8 rows in set (0.00 sec)

    执行SET NAMES gbk; 命令后,再来查看一下当前连接系统参数:

    mysql> SET NAMES GBK;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> show variables like 'char%';
    +--------------------------+---------------------------------------------------------+
    | Variable_name            | Value                                                   |
    +--------------------------+---------------------------------------------------------+
    | character_set_client     | gbk                                                     |
    | character_set_connection | gbk                                                     |
    | character_set_database   | latin1                                                  |
    | character_set_filesystem | binary                                                  |
    | character_set_results    | gbk                                                     |
    | character_set_server     | latin1                                                  |
    | character_set_system     | utf8                                                    |
    | character_sets_dir       | C:\Program Files\MySQL\MySQL Server 5.5\share\charsets\ |
    +--------------------------+---------------------------------------------------------+
    8 rows in set (0.00 sec)

    可以看到,受影响的只有客户端的三条记录: character_set_client、character_set_connection、character_set_results,而真正服务器端的编码字符集,character_set_server 和 character_set_database ,set names 'xxx' 根本无法没有收到影响。

    那么在5-1节中,当时为什么要输入这条指令呢?因为我在教程刚开始的时候,就在my.ini中将MySQL的默认编码方式为utf-8,所以这里需要在客户端以gbk的编码显示数据防止乱码,只影响客户端的显示方式,不影响数据表实际的数据

    而我的小伙伴刚开始的时候没有将默认的编码方式设置为utf-8,仍然采用latin1,但是他又输入了SET NAMES gbk;命令,所以导致出现了1366错误

    六.  根本解决方法

    根本的解决方法其实很简单:

    如果MySQL默认编码为latin1,则不要执行SET NAMES gbk;

    如果MySQL默认编码为utf8,则执行SET NAMES gbk;命令后再插入记录

    另外值得注意的是:

    修改my.ini一定要记得重启MySQL服务

    通过my.ini更改MySQL默认编码后,如果不重启MySQL服务,则新创建的数据库依旧是更改前的MySQL编码

    如果重启服务,新创建的数据库才会变成更改后的MySQL编码,但是之前创建的数据库依旧是是更改前的MySQL编码

    七.  参考资料

    digdeep博客

    ACMAIN_CHM博客

    badkano的知道回答

  • 0
  • 0
  • 0
  • 1.8w
  • 梁兴健

    请登录之后再进行评论

    登录
    单栏布局 侧栏位置: