新来了一位同事,搞崩了用户管理功能。。

3 篇文章 0 订阅

新来了一位同事,搞崩了用户管理功能。。

0. 背景

笔者所在的公司是有一个统一的人力资源系统,因为公司业务系统比较多,所以各个业务系统都是凌晨启动定时任务,向人力资源系统请求数据,同步所有的用户数据。

这个礼拜有一天起床看手机,看到了用户同步任务失败的消息,错误信息大概如下(笔者模拟):

Incorrect string value: '\xF0\xA4\xA7\x9F' for column 'user_name'

这么看报错信息推测应该是用户名编码格式有问题,\x开头那应该是utf16编码,于是笔者用网页工具解码后如下,解码后是一个 “𤧟”。好吧,这个字看着不复杂,但却没有搜索到太多的信息,百度词条也没有收录,这是一个生僻字(应该念tíng吧)。

UTF16编码

1. 问题模拟

1.1 环境

MySQL 5.7.36(不说环境都是耍流氓)

1.2 数据表

模拟数据表结构如下,下文以此表进行演练:

CREATE TABLE `system_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `user_id` varchar(32) NOT NULL COMMENT '用户id',
  `user_name` varchar(128) NOT NULL COMMENT '用户名称',
  `created_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表'

1.3 数据保存

insert into `system_user` (user_id, user_name) values('U00001', '赵珊𤧟');

报错信息:

org.jkiss.dbeaver.model.sql.DBSQLException: SQL 错误 [1366] [HY000]: Incorrect string value: '\xF0\xA4\xA7\x9F' for column 'user_name' at row 1
	...
	... 12 more

1.4 查询

这里补充一个,因为笔者负责的系统用户同步失败了,于是乎跑到隔壁同事负责的系统查询这个用户是否存在。结果。。。

select * from `system_user` where user_name like '%𤧟%';

查询结果:

Incorrect string value: '\xF0\xA4\xA7\x9F' for column 'user_name' at row 1
Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation 'like'

2. 原因分析

这里直接说问题吧,简单讲就是MySQL默认字符集为utf8,而utf8最多为3个字节,但特殊符号(包括生僻字)为4个字节,比如上面的“𤧟”字。所以保存数据到MySQL的时候便报错了。

其实在笔者的开发工作也遇到过类似的情况,测试人员在搜索框中输入表情符号(这种:☹☂✌),结果搜索失败,跟我们说这是bug让我们改,笔者同事都开始磨刀了,当初报的就是类似的错误,提示了一个utf16的编码信息。

3. 解决方案

知道了是长度不够造成无法存储特殊字符,那我们来修改字符集即可,这里有两种字符集编码可供大家选择,utf16utf8mb4utf16编码占4个字节;utf8mb4全名为:utf8 most bytes 4,最多为4个字节,即它是utf8的升级,utf8可以看成是utf8mb4的一个子集。

-- 方案1,修改整个表的字符集编码
ALTER TABLE `system_user` DEFAULT CHARSET=utf8mb4;

-- 方案2,修改user_name字段的字符集编码
ALTER TABLE `system_user` MODIFY COLUMN user_name varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名称';

这里笔者选用第二种方案进行测试,修改字符集编码后再1.3的插入语句,结果成功。

insert into `system_user` (user_id, user_name) values('U00001', '赵珊𤧟');

insert

然后我们再来执行1.4的查询语句:

select * from `system_user` where user_name  like '%𤧟%';

select

4. 巨人的肩膀

科普文,写的很不错,可以翻阅复习:Unicode 编码及 UTF-32, UTF-16 和 UTF-8

明天去踏春~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值