MySQL插入emoji表情失败问题的解决方法
前言
之前一直认为UTF-8是万能的字符集问题解决方案,直到最近遇到这个问题。最近在做新浪微博的爬虫, 在存库的时候发现只要保持emoji表情,就回抛出以下异常:
Incorrect string value: '\xF0\x90\x8D\x83\xF0\x90...'
众所周知UTF-8是3个字节, 其中已经包括我们日常能见过的绝大多数字体. 但3个字节远远不够容纳所有的文字, 所以便有了utf8mb4, utf8mb4是utf8的超集, 占4个字节, 向下兼容utf8. 我们日常用的emoji表情就是4个字节了.
所以在此我们像utf8的数据表插入数据就会报出Incorrect string value这个错误.
Google一下很容易就找到了解决方案, 具体解决办法是如下:
一、修改数据表的字符集为utf8mb4
这点很简单, 修改语句网上找一大堆, 不过建议重新建表, 使用 mysqldump -uusername -ppassword database_name table_name > table.sql 备份相应数据表, 并修改其中的建表语句的字符集为 utf8mb4 即可, 然后 mysql -uusername -ppassword database_name < table.sql 重新导入sql即可完成修改字符集操作.
二、MySQL数据库版本要5.5.3及以上
网络上所有的文章都说明要MySQL 5.5.3以上的版本才支持utf8mb4, 不过我使用的数据库版本为5.5.18, 最终仍能解决问题, 所以同学们不要急着找运维哥哥升级数据库先, 先试试能不能自己解决问题.
三、修改数据库配置文件/etc/my.cnf并重启mysql服务
主要是修改数据库的默认字符集, 以及连接, 查询的字符集, [Mysql支持emoji 表情符号 升级编码为UTF8MB4][1] 这篇文章有详细的设置方法, [深入Mysql字符集设置][2] 这篇文章有其中设置的各个字符集的作用, 大家可以科普下.
四、升级MySQL Connector到5.1.21及以上
以上所有的操作, 最关键的是步骤3, 修改数据库的配置文件, 其中大概修改了
[client]
# 客户端来源数据的默认字符集
default-character-set = utf8mb4
[mysqld]
# 服务端默认字符集
character-set-server=utf8mb4
# 连接层默认字符集
collation-server=utf8mb4_unicode_ci
[mysql]
# 数据库默认字符集
default-character-set = utf8mb4
这些配置指定了数据从客户端到服务端所经过的一条条管道使用的字符集, 其中每一个管道出现问题都可能会导致插入失败或者乱码.
但很多时候, 线上的数据库是不能随便修改数据库文件的, 所以我们的运维同学很果断的回绝了我修改数据库配置文件的请求(T_T)
所以就只能用代码解决了, 一开始是准备从JDBC连接时候就指定使用的字符集处下手.
jdbc:mysql://localhost:3306/ding?characterEncoding=UTF-8
主要把UTF-8修改为utf8mb4对于的Java Style Charset字符串应该就能解决问题吧?
不过很遗憾的是, Java JDBC并不存在utf8mb4对于的字符集. 使用UTF-8的时候可以兼容urf8mb4并自动转换字符集.
For example, to use 4-byte UTF-8 character sets with Connector/J, configure the MySQL server with character_set_server=utf8mb4, and leave characterEncoding out of the Connector/J connection string. Connector/J will then autodetect the UTF-8 setting. – [MySQL:Using Character Sets and Unicode][3]
后来科普了一下, 在每一次查询请求的时候, 可以显式的指定使用的字符集, 使用 set names utf8mb4 可以指定本次链接的字符集为utf8mb4, 但这个设置在每次连接被释放后都会失效.
目前的解决办法是, 在需要插入utf8mb4的时候, 显示地调用执行set names utf8mb4, 如:
jdbcTemplate.execute("set names utf8mb4");
jdbcTempalte.execute("...");
需要注意的是, 我们在使用一下ORM框架的时候, 因为性能优化原因, 框架会延迟提交, 除非事务结束或者用户主动调用强制提交, 负责执行的set names utf8mb4仍然不会生效.
在这里我使用的是myBatis, 以MessageDao为例
// MessageDao
public interface MessageDao {
@Update("set names utf8mb4")
public void setCharsetToUtf8mb4();
@Insert("insert into tb_message ......")
public void insert(Message msg);
}
// test code
SqlSession sqlSession = sqlSessioFactory.openSession();
messageDao = sqlSession.getMapper(MessageDao.class);
messageDao.setCharsetToUtf8mb4();
// 强制提交
sqlSession.commit();
messageDao.insert(message);
至此, 问题便解决了..
哎, 如果世事能那么顺利就好了, 在项目中, mybatis是实例是交由Spring去管理的, 也就是说我拿不到sqlSession, 也就是强制提交不了. 并且因为Spring事务框架的限制, 他并不允许用户显式调用强制提交. 目前还在纠结这个问题.
有两个解决思路:
- 使用AOP, 在可能插入4字节UTF8字符的时候, 前置方法执行
set names utf8mb4, 但该方案还不能确定AOP的方法会被Spring进行事务管理么, 并且在前置方法中,拿到的链接是否和接下来拿到的连接对象是同一个session. - 研究Spring JDBC的创建方法, 写一个hook在每次创建新的数据库连接的时候, 都执行一次
set names utf8mb4, 这样就保证每一次拿到的链接都是设置过字符集的.
总结
以上就是这篇文章的全部内容了,待有时间再实验一下以上两种方案。希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
MySQL插入emoji表情失败问题的解决方法的更多相关文章
- mysql创建外链失败1005错误解决方法
mysql创建外链失败1005错误解决方法 错误号:1005错误信息:Can't create table 'webDB.#sql-397_61df' (errno: 150)解决方法 错误原因有四: ...
- 一个emoji引发的一条血案:mysql存储emoji表情字符时报错解决
以下是我插入一条带表情的数据到mysql后出现错误 2019-03-04 14:24:40,462 ERROR 2807 [-/139.199.27.244/-/2ms POST /api/activ ...
- MySQL插入emoji表情报错 SQLException: Incorrect string value 的两种解决方案
摘抄自:https://blog.csdn.net/dmw412724/article/details/81119325 原因:mysql的UTF-8只支持三个字节的存储,而一般字符是三个字节,但是e ...
- Mysql插入Emoji表情出错
Caused by: java.sql.SQLException: Incorrect at com.mysql.jdbc.SQLError.createSQLException(SQLError.j ...
- mysql不支持emoji表情的问题的解决方法
最近财神圈项目集成微信登录功能的过程中,当保存用户有昵称含有表情符号时后台服务抛出异常,原来是数据库默认字符集不支持emoji表情字符.找到问题的原因后,因为之前也没有遇到过这样的问题,也没思路,迅速 ...
- mysql存储emoji表情报错的处理方法【更改编码为utf8mb4】
utf-8编码可能2个字节.3个字节.4个字节的字符,但是MySQL的utf8编码只支持3字节的数据,而移动端的表情数据是4个字节的字符.如果直接往采用utf-8编码的数据库中插入表情数据,Java程 ...
- MySQL解决插入emoji表情失败的问题
普通的字符串或者表情都是占位3个字节,所以utf8足够用了,但是移动端的表情符号占位是4个字节,普通的utf8就不够用了,为了应对无线互联网的机遇和挑战.避免 emoji 表情符号带来的问题.涉及无线 ...
- MySQL 插入emoji 表情
create table doctorUserInfoMation ( id int not null auto_increment comment '系统ID', userId ) comment ...
- mysql插入数字都变成2147483647的解决方法
2147483647是int类型的最大值,所以插入11位的数字都会变成2147483647,把int改为bigint即可
随机推荐
- loj#6235. 区间素数个数(min25筛)
题意 题目链接 Sol min25筛的板子题,直接筛出\(g(N, \infty)\)即可 筛的时候有很多trick,比如只存\(\frac{N}{x}\)的值,第二维可以滚动数组滚动掉 #inclu ...
- Android Studio查看签名文件sha1和MD5的方法
Android在生成了应用签名文件后,如果我们想要查看签名文件的sha1和md5,该怎么操作呢??下面我们来看看. 把android studio界面左下角的Terminal终端窗口打开,进入JDK的 ...
- 如何从 GitHub 上下载单个文件夹
DownGit 好用记得回来点赞(建议***)
- canvas验证码 - 滑块拼图
滑块拼图型的验证方式已经流行起来,多数的实现方式是直接加载两张分割好的图片.现在用canvas去自动修剪图片,节省修图工作量和http请求: 加载一张整图,用canvas切割缺口,缺口位置在固定范围内 ...
- Android手势密码实现
图 二.实现思路: 1. 正上方的提示区域,用一个类(LockIndicator.java)来实现,自定义view来绘制9个提示图标: 2. 手势密码绘制区域,用一个类(GestureContentV ...
- Java 8方法引用使用指南
[编者按]本文作者为拥有15年 Java 开发经验的资深程序员 Per-Åke Minborg,主要介绍如何灵活地解析 Java 中的方法引用.文章系国内 ITOM 管理平台 OneAPM 编译呈现. ...
- mysql常用语句备忘
1.连接本地数据库 mysql -h localhost -u root -p123 2.连接远程数据库 mysql -h 192.168.0.201 -P 3306 -u root -p123 3. ...
- zabbix系列之四——快速使用
https://www.zabbix.com/documentation/3.4/manual/quickstart/login Quickstart 1login and configuring u ...
- spring boot(17)-@Async异步
验证码的异步机制 上一篇讲过可以用邮件发验证码,通常我们在某网站发验证码时,首先会提示验证码已发送,请检查邮箱或者短信,这就是图中的1和3.然而此时查看邮箱或短信可能并没有收到验证码,往往要过几秒种才 ...
- WEBserver 性能测试
本地实验(Centos7),WEBserver性能测试; 软件包地址 wget http://download.joedog.org/siege/siege-4.0.2.tar.gztar -xf s ...