SpringBoot+Mysql 无法保存emoj表情?

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 尤记得很久以前,想存 emoj 表情到 mysql 中,需要额外的将 emoj 表情转码之后保存,每次读取时,再解码还原成一下;每次这种 sb 的操作,真心感觉心塞,那么有没有办法直接存呢?

尤记得很久以前,想存 emoj 表情到 mysql 中,需要额外的将 emoj 表情转码之后保存,每次读取时,再解码还原成一下;每次这种 sb 的操作,真心感觉心塞,那么有没有办法直接存呢?


mysql 本身可以通过选择编码集(如 utfbmb4)来支持 emoj 表情,然而今天遇到了一个相当鬼畜的问题,表中可以直接写入 emoj 表情,但是通过 spring boot 代码塞入的 emoj 时,却抛出异常:


Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x9D\xE6\xB1...' for column 'nick' at row 1
  at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1084) ~[mysql-connector-java-5.1.30.jar:na]
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4232) ~[mysql-connector-java-5.1.30.jar:na]
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4164) ~[mysql-connector-java-5.1.30.jar:na]
  at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615) ~[mysql-connector-java-5.1.30.jar:na]
  at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776) ~[mysql-connector-java-5.1.30.jar:na]
  at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2838) ~[mysql-connector-java-5.1.30.jar:na]
  at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2082) ~[mysql-connector-java-5.1.30.jar:na]
复制代码


接下来演示一下正确的使用姿势,以及导致上面问题的错误 case,避免大家重复采坑


I. Emoj 表情支持之旅



接下来我们的目标是可以直接向 mysql 中读取或写入 emoj 表情


1. 表字符集


首先针对 mysql 表,需要指定字符集为utfbmb4


CREATE TABLE `Subscribe` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(140) NOT NULL DEFAULT '',
  `nick` varchar(30) NOT NULL DEFAULT '昵称',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 订阅未激活, 1 订阅已激活 , 2 取消订阅',
  `created` int(13) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `updated` int(13) NOT NULL DEFAULT '0' COMMENT '更新时间'
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
复制代码


上面直接设置表的字符集为utf8mb4,如果某个表已经存在,但是字符集不是 utf8mb4,这种 case 下我们也可以单独的设置某个列的编码如下


ALTER TABLE `Subscribe` CHANGE `nick` `nick` VARCHAR(30)  CHARACTER SET utf8mb4 NOT NULL  DEFAULT '';
复制代码


如上设置之后,我们可以直接在这个表中添加 emoj


image.png


2. SpringBoot 支持


接下来进入正题,springboot 项目,如何支持 emoj 的插入;首先看一下项目依赖


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>
<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot-local</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
复制代码


我们使用的是2.2.1.RELEASE版本,请确保引入了依赖spring-boot-starter-jdbcmysql-connector-java


然后配置 db 相关属性, application.properties


## DataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=
复制代码


然后就可以愉快的进行测试了


@Slf4j
@SpringBootApplication
public class Application {
    public Application(JdbcTemplate jdbcTemplate) {
        log.warn("application start!!!");
        // 插入emoj 表情
        jdbcTemplate.update("insert into Subscribe (`email`, `nick`) values (?, ?)",
                UUID.randomUUID().toString() + "@t.com", "🐺狼");
        List<Map<String, Object>> r = jdbcTemplate.queryForList("select * from Subscribe order by id desc limit 2");
        log.info("r: {}", r);
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}
复制代码


实测结果如下


image.png


这个不已经插入成功了么,那么问题来了,本文开头的那个异常是怎么回事呢


3. 场景复现


出现文章开头的问题,主要是由于mysql-connector-java的版本问题导致的,我们来复现一下,首先将版本指定为5.1.30 (因为我们内部使用的就是这个版本,所以采坑了...)


<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.30</version>
</dependency>
复制代码


其次需要在环境配置中,指定一下driver-class-name


spring.datasource.driver-class-name= com.mysql.jdbc.Driver
复制代码


注意


这里需要说明一下,在更高的mysql-connector-java版本中,已经改成com.mysql.cj.jdbc.Driver这个类了;如果依旧配置上面的 Driver,在执行时会有一行提示


image.png

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
复制代码


最后再次执行前面的测试代码,异常就来了

image.png


4. 小结


在 mysql 中存入 emoj 表情的场景可以说比较多了,毕竟 21 世纪了,不支持 emoj 的应用是没有前途的;通过前面的 case,即介绍了如何正确的让 springboot 应用支持 emoj 表情,也给出了一个由于版本问题导致的坑


emoj 支持步骤


  • 首先是源头支持,需要修改 mysql 的表字符集;或者修改某些列的字符集,设置为 utf8mb4
  • 注意引入的mysql-connector-java版本,务必选择比较新的版本,
  • springboot2.2.1.RELEASE默认提供的版本为8.0.18
  • 而我们演示中的 5.1.30 则不支持 emoj 插入
  • 驱动类,新版中已经使用com.mysql.cj.jdbc.Driver替换之前的com.mysql.jdbc.Driver



相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
20天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
25天前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
45 5
|
1月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
57 8
|
1月前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
65 9
|
2月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
254 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
2月前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
94 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
|
1月前
|
关系型数据库 MySQL Java
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
34 0
|
3天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
13 3
|
3天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
20 3
|
3天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE &#39;log_%&#39;;`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
25 2