尤记得很久以前,想存emoj表情到mysql中,需要额外的将emoj表情转码之后保存,每次读取时,再解码还原成一下;每次这种sb的操作,真心感觉心塞,那么有没有办法直接存呢?
mysql本身可以通过选择编码集(如utfbmb4)来支持emoj表情,然而今天遇到了一个相当鬼畜的问题,表中可以直接写入emoj表情,但是通过spring boot代码塞入的emoj时,却抛出异常:
1 2 3 4 5 6 7 8 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
1 2 3 4 5 6 7 8 9 10 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下我们也可以单独的设置某个列的编码如下
1 ALTER TABLE `Subscribe` CHANGE `nick` `nick` VARCHAR (30 ) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' ;
如上设置之后,我们可以直接在这个表中添加emoj
2. SpringBoot支持 接下来进入正题,springboot项目,如何支持emoj的插入;首先看一下项目依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.2.1.RELEASE</version > <relativePath /> </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-jdbc
与 mysql-connector-java
然后配置db相关属性, application.properties
1 2 3 4 ## 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=
然后就可以愉快的进行测试了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Slf 4j@SpringBootApplication public class Application { public Application (JdbcTemplate jdbcTemplate) { log.warn("application start!!!" ); 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 ) ; } }
实测结果如下
这个不已经插入成功了么,那么问题来了,本文开头的那个异常是怎么回事呢
3. 场景复现 出现文章开头的问题,主要是由于mysql-connector-java
的版本问题导致的,我们来复现一下,首先将版本指定为5.1.30
(因为我们内部使用的就是这个版本,所以采坑了…)
1 2 3 4 5 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency>
其次需要在环境配置中,指定一下driver-class-name
1 spring.datasource.driver-class-name= com.mysql.jdbc.Driver
注意
这里需要说明一下,在更高的mysql-connector-java
版本中,已经改成com.mysql.cj.jdbc.Driver
这个类了;如果依旧配置上面的Driver,在执行时会有一行提示
1 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.
最后再次执行前面的测试代码,异常就来了
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
II. 其他 0. 项目
1. 一灰灰Blog 尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
一灰灰blog
Be the first person to leave a comment!