如何让MySql数据库支持emoji表情

955 阅读5分钟

如何让MySql数据库支持emoji表情

1. 字符集

1.1 字符集的分类

  1. MySQL可以在服务器上、数据库、表、字段上指定字符编码
  2. 在服务器上指定字符编码是安装服务器的时候指定的
  3. 数据库、表、字段上是创建时候指定的

常用的字符集有:

gbk,gb2312,utf8,utf8mb4

utf-8

通常情况,Mysql数据编码格式为“utf-8”,对于汉字来说足够;Mysql中utf8占3个字节,但是,3个字节对于表情符号是不够的,需4个字节;此时使用utf8,会出现‘\xF0\x9F\x8D\x83\xF0\x9F’的问题。

utf8mb4

utf8mb4编码是utf8编码的超集,兼容utf8,并且能存储4字节的表情字符。

1.2 如何查看字符集

  1. 查看MYSQL数据库服务器和数据库字符集

    方法一:show variables like '%character%';
    方法二:show variables like 'collation%';
    
    1. 方法1:

      mysql> show variables like '%character%';
      
      +--------------------------+--------------------------------------+
      
      | Variable_name            | Value                                |
      
      +--------------------------+--------------------------------------+
      
      | character_set_client     | utf8                                 |
      
      | character_set_connection | utf8                                 |
      
      | character_set_database   | utf8                                 |
      
      | character_set_filesystem | binary                               |
      
      | character_set_results    | utf8                                 |
      
      | character_set_server     | utf8                                 |
      
      | character_set_system     | utf8                                 |
      
      | character_sets_dir       | /usr/local/mysql5535/share/charsets/ |
      
      +--------------------------+--------------------------------------+
      
      8 rows in set (0.00 sec)
      
    2. 方法2:

      mysql> show variables like 'collation%';
      
      +----------------------+-----------------+
      
      | Variable_name        | Value           |
      
      +----------------------+-----------------+
      
      | collation_connection | utf8_general_ci |
      
      | collation_database   | utf8_general_ci |
      
      | collation_server     | utf8_general_ci |
      
      +----------------------+-----------------+
      
      3 rows in set (0.00 sec)
      
  2. 查看库的字符集

    语法:show create database 数据库\G;
    
    mysql> show create database shiyan\G
    
    *************************** 1. row ***************************
    
           Database: shiyan
    
    Create Database: CREATE DATABASE `shiyan` /*!40100 DEFAULT CHARACTER SET gbk */
    
    1 row in set (0.00 sec)
    
  3. 查看表的字符集

    语法:show table status from 库名 like 表名;
    
    mysql> show table status from class_7 like 'test_info';
    
    +-----------+--------+---------+------------+------+----------------+-------------------------+-------------+------------+-----------------+----------+-
    
    | Name      | Engine | Version | Row_format | Rows | Avg_row_length | Data_leate_time         | Update_time | Check_time | Collation       | Checksum | 
    
    +-----------+--------+---------+------------+------+----------------+-------------------------+-------------+------------+-----------------+----------+-
    
    | test_info | InnoDB |      10 | Compact    |   10 |           1638 |       17-12-05 19:01:55 | NULL        | NULL       | utf8_general_ci |     NULL | 
    
    +-----------+--------+---------+------------+------+----------------+-------------------------+-------------+------------+-----------------+----------+-
    
    1 row in set (0.00 sec)
    
  4. 查看表中所有列的字符集

    语法:show full columns from 表名;
    
    mysql> show full columns from test_info;
    
    +-------+----------+-----------------+------+-----+---------+-------+---------------------------------+---------+
    
    | Field | Type     | Collation       | Null | Key | Default | Extra | Privileges                      | Comment |
    
    +-------+----------+-----------------+------+-----+---------+-------+---------------------------------+---------+
    
    | id    | int(3)   | NULL            | NO   | PRI | NULL    |       | select,insert,update,references |         |
    
    | name  | char(12) | utf8_general_ci | YES  |     | NULL    |       | select,insert,update,references |         |
    
    | dorm  | char(10) | utf8_general_ci | YES  |     | NULL    |       | select,insert,update,references |         |
    
    | addr  | char(12) | utf8_general_ci | YES  |     | 未知    |       | select,insert,update,references |         |
    
    | score | int(3)   | NULL            | YES  |     | NULL    |       | select,insert,update,references |         |
    
    +-------+----------+-----------------+------+-----+---------+-------+---------------------------------+---------+
    
    5 rows in set (0.00 sec)
    

1.3 字符集的解释

  • 查询结果如下图:

image.png

系统变量: – character_set_client: 客户端来源数据使用的字符集

– character_set_connection: 连接层字符集

– character_set_database: 当前选中数据库的默认字符集

– character_set_results: 查询结果字符集

– character_set_filesystem: 用于没有字符集导入符的文字和数字-字符串转换

– character_set_server: 默认的内部操作字符集

– character_set_system: 系统元数据(字段名等)字符集

– 还有以collation_开头的同上面对应的变量,用来描述字符序。

系统变量,在MySQL架构图中的位置:

image.png

1.4 如何修改字符集

1. 针对字段修改编码格式(推荐使用)

  • 数据库表对应字段上修改编码格式为**utf8mb4,**命令示例如下:
  ALTER TABLE insure_user CHANGE nickname nickname VARCHAR(64) CHARACTER SET utf8mb4 ; 

2. 可视化工具,Navicat 设计表示例:

  • 改字段字符集

image.png

  • 改表字符集

image.png

  • 改datebase字符集

image.png

2. 排序规则的选择

todo

3. 为什么MySql数据库不支持emoji表情

  • MYSQL 插入表情符号时,报异常:

java.sql.BatchUpdateException: Incorrect string value: '\xF0\x9F\x8D\x83\xF0\x9F...' for column 'nickname' at row 1

  • 原因:

    通常情况,Mysql数据编码格式为“utf-8”,对于汉字来说足够;Mysql中utf8占3个字节,但是,3个字节对于表情符号是不够的,需4个字节;此时使用utf8,会出现‘\xF0\x9F\x8D\x83\xF0\x9F’的问题。

4. 支持emoji表情的两种方法

前提:修改相应字段的字符集改为utf8mb4

首先,两种方法实现的前提是:先修改相应字段的字符集改为utf8mb4( 修改方法见1.4 )

4.1 java配置文件增加“connection-init-sql: set names utf8mb4”

相应字段的字符集修改为utf8mb4后,在java服务的yml配置文件中,数据库连接信息增加:

connection-init-sql: set names utf8mb4

如图:

image.png

测试结果:

image.png

总结:

  1. 是否能够插入表情,不仅仅要求相关的字段是utf8mb4编码格式,utf8mb4仅仅只是前提
  2. 除了要求字段的格式是utf8mb4,还要求当前的session会话连接的编码同时是utf8mb4
  3. set name utf8mb4 只对当前会话有效,不影响其他连接和全局的配置

这么做的原理分析:connectionInitSqls 是用来干嘛的,为什么配置一个这个就可以了?

connectionInitSqls 是druid 数据库特有的配置(查看官方文档说明该参数是在初始化连接时执行的sql),

那这样就很好理解了,当我们执行set name utf8mb4之后就在当前session 中一直使用utf8mb4的编码格式

image-20200601175817141

druid 数据源在初始化连接之后,还会进行配置的initSql初始化,在这次初始化里,用户设置了set names utf8mb4 之后,就会指定了最终的字符集。

4.2 修改Server端 character_set_server的字符集,并重启

查看MySQL官方文档,发现这么一句话:

​ Connector/J now auto-detects servers configured with character_set_server=utf8mb4 or treats the Java encoding utf-8 passed using characterEncoding=... as utf8mb4 in the SET NAMES= calls it makes when establishing the connection

意思大概是:java 会自动检测 MySQL系统参数:character_set_server的字符集来编码

所以,我们来修改MySQL Server端的字符集,重启数据库后,也能实现 emoji标清的插入:

修改Mysql配置文件my.cnf(windows下为my.ini),然后重启数据库

[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'

总结:

  1. 是否能够插入表情,不仅取决于字段的编码格式,还有当前session会话的编码格式 或 MySQL Server端的编码格式
  2. 不论哪种方法,前提都是先将相应字段的字符集改为utf8mb4
  3. 然后 4.1 、 4.2方法,二选一执行即可

记录:4.1方法,java服务采用 手动创建数据库连接时,解决方案:

背景是:我手头的 java项目用到了多数据源(2个MySQL + 1个sqlServer),所以在建立数据库连接时,采用的是配置类 手动创建的;

@Primary
    @Bean(name = "orderDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.order")
    public DataSource orderDataSource() {
       
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }

这样就导致,我在配置文件增加“connection-init-sql: set names utf8mb4”,不会在创建连接时,被使用到;导致会话连接的编码格式没有修改成功;

解决方式:

配置类创建连接的方法中,手动增加 set names utf8mb4,如下:

@Primary
    @Bean(name = "orderDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.druid.order")
    public DataSource orderDataSource() {
       
         // 建立数据库连接时,设置utf8mb4编码。目的兼容 emoji表情
        dataSource.setConnectionInitSqls(new ArrayList<String>() {{ add("set names utf8mb4;");}});
        return dataSource;
    }