• 解决一个Mysql的utf8编码导致的问题


    1、问题背景

    在一个基于NLP(自然语言处理)算法分析用户诉求的系统中,使用了 Mysql作为数据库储存来自其他各系统的用户反馈,数据库编码统一设置为utf8。在运行过程中,偶尔出现数据库异常,主要表现为:Incorrect string value: ‘\xF0\x9F\x8D\x83…’ for column ‘xxx’。

    2、分析问题

    '\xF0\x9F\x8D\x83’的二进制以11110开头,是一个4字节的utf8字符,通过查阅相关资料,了解到Mysql的utf8编码只能支持到3字节,当存入4字节字符时,便会出现以上异常。正常情况下,英文或汉字的字符都在3字节以内编码,4字节编码的字符一般是表情符号。

    3、解决问题

    3.1、方式1 - 修改编码方式

    utf8mb4编码是utf8编码的超集,兼容utf8,且能存储4字节的表情字符。将Mysql数据库编码格式修改为utf8mb4,JDBC连接时声明编码为utf8mb4,可以解决以上问题。

    3.2、方式2 - 移除4字节字符

    在我们这个系统中,由于采用NLP算法,仅基于文本分析语义,表情符号不影响最终结果,可以忽略,故可以在入库前移除4字节字符。

    utf8是不定长的编码格式,1-4字节都有各自的特定格式。
    1字节格式:0xxxxxxx
    2字节格式:110xxxxx, 10xxxxxx
    3字节格式:1110xxxx, 10xxxxxx, 10xxxxxx
    4字节格式:11110xxx, 10xxxxxx, 10xxxxxx, 10xxxxxx

    通过以上格式可知,只有4字节拥有11110xxx字节,所以只需要检测字节流中是否存在11110xxx字节,如果有则将该字节以及之后的3个字节删除。代码如下:

    public static String remove4ByteChar(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        byte[] bytes = s.getBytes();
        List byteList = new ArrayList<>();
        for (int i = 0; i < bytes.length; i++) {
            // UTF-8的4字节编码以11110开头
            if ((bytes[i] & 0xF8) == 0xF0) {
                i += 3;
            } else {
                byteList.add(bytes[i]);
            }
        }
        bytes = new byte[byteList.size()];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = byteList.get(i);
        }
        return new String(bytes);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    数仓工具—Hive进阶之性能优化最佳实践(22)
    Kinodynamic RRT-connect(Rapidly-exploring Random Tree-Connect)算法例子
    Python实现BrainFxxk虚拟机
    【Spring】静态代理
    创维E900V22E_卡刷固件及升级说明
    超详细Python教程——修改和增加类属性
    王道第二章算法部分代码总结-个人使用
    CSS动画(动态导航栏)
    SpringBoot AOP + Redis 延时双删功能实战
    7-2 图着色问题
  • 原文地址:https://blog.csdn.net/vipshop_fin_dev/article/details/126071107