解决mysql 模糊搜索表情包 编码报错 Illegal mix of collations

需求: 对微信Id和微信名称进行模糊搜索,搜索字段中可能会出现表情
问题: mysql 中对微信名中进行模糊搜索会出现mysql编码报错,wx_id字段会报错,nickname字段不会。
SELECT
	wx_id 
FROM
	wx_fans 
WHERE
	wx_id LIKE '💊' or nickname LIKE '💊'

Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,COERCIBLE) for operation 'like'

排查后发现是字段编码不同wx_id( utf8_general_ci) nickname(utf8mb4_general_ci)
两者区别:MySQL在5.5.3之后增加了utf8mb4的编码,mb4就是dumost bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。
在这里插入图片描述

解决方案:
1.修改Mysql字段编码
2.在Java代码层面解决
  • 用一个表情编码器来判断查询 字段中是否包含表情
public static boolean containsEmoji(String source) {
    int len = source.length();
     boolean isEmoji = false;
     for (int i = 0; i < len; i++) {
         char hs = source.charAt(i);
         if (0xd800 <= hs && hs <= 0xdbff) {
             if (source.length() > 1) {
                 char ls = source.charAt(i + 1);
                 int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                 if (0x1d000 <= uc && uc <= 0x1f77f) {
                     return true;
                 }
             }
         } else {
             // non surrogate
             if (0x2100 <= hs && hs <= 0x27ff && hs != 0x263b) {
                 return true;
             } else if (0x2B05 <= hs && hs <= 0x2b07) {
                 return true;
             } else if (0x2934 <= hs && hs <= 0x2935) {
                 return true;
             } else if (0x3297 <= hs && hs <= 0x3299) {
                 return true;
             } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d
                     || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c
                     || hs == 0x2b1b || hs == 0x2b50 || hs == 0x231a) {
                 return true;
             }
             if (!isEmoji && source.length() > 1 && i < source.length() - 1) {
                 char ls = source.charAt(i + 1);
                 if (ls == 0x20e3) {
                     return true;
                 }
             }
         }
     }
     return isEmoji;
 }
  • 如果有表情 => nickname模糊搜索,没用表情包 =>nickname或wxId模糊搜索。(wxId中不会有表情,没必要搜索,但不知道用户输入的是wxId还是nickname)
问题:使用正常直到遇到了一个新的表情🦄,排除原因后发现,表情编码器中的表情能判断的表情是有限的,不能保证用户所搜索的表情都包含在内。
解决方案:

先使用wxId和nickname执行一遍模糊查询,如果报指定的异常,说明搜索中包含这个表情,再捕获异常,只用wxId进行模糊搜索

try {
    aiRepeatFriends = aiAssistantManagementMapper.repeatFriendsMonitor(req.getQuery(), comId, req.buildRowBounds(), groupId, emjor);
} catch (Exception e) {
	log.info("存在未知表情,搜索失败 请求数据:{}", JSON.toJSONString(req));
	log.error("错误详情:{}",e);
	if(e.getMessage().contains("Illegal mix of collations")){
       emjor = "emjor";
       aiRepeatFriends = aiAssistantManagementMapper.repeatFriendsMonitor(req.getQuery(), comId, req.buildRowBounds(), groupId, emjor);
    }else{
          throw e;
   }
}
问题: 在搜索时又遇到了一个新问题,用一个表情进行搜索,却把其他表情结果也都搜索出来了
解决方案:mysql二进制搜索(其实只要用了二进制搜索也不会编码报错)
BINARY(wgf.nickname) LIKE #{search}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值