mysql中Incorrectstringvalue乱码问题解决方案转载

原创
小哥 3年前 (2022-10-27) 阅读数 65 #大杂烩

您是否遇到过类似的错误?

java.sql.SQLException: Incorrect string value: \xF0\x9F\x92\x9C for column content at row 1.

出现这种反常现象的原因是,mysql中的utf8该代码最多只能使用。3如果是字符,则字节存储字符。utf8

编码占用4字节(最常见ios中的emoji表达式字符),则在写入数据库时将报告错误。

mysql从5.5.3仅在开始时支持该版本。4字节的utf8代码,具有代码名utf8mb4(mb4的意思是max bytes 4),这种编码方法是最常用的。4字节存储一个字符。

要证明这个问题,您可以执行以下操作。sql:

select * from
information_schema.CHARACTER_SETS
where CHARACTER_SET_NAME like utf8%

结果如下:

因此,为了解决上述异常的发生,有必要使用utf8mb4编码。

在解析数据库编码后,客户端也需要解析。ConnectionConnection对象使用的编码问题。

已创建呼叫。Connection对象执行以下操作sql:

conn.createStatement().execute("SET names utf8mb4");

如果项目使用DataSource数据源,只需要在这里配置数据源。apache的DBCP中以数据源为例进行了说明。spring该框架配置如下:


    
        
        
        
        
        
        
        
        
        
        
        
        
            
                set names utf8mb4
            
        
    

以下解释引用自mysql参考手册:

SET NAMES charset_name

SET NAMES显示发送的客户端。SQL语句中使用的是什么字符集。

因此,SET NAMES utf8mb4该语句告诉服务器:“将来,来自该客户端的信息将使用一个字符集。”utf8mb4“。它还指定服务器发回给客户端的结果的字符集。(例如,如果使用SELECT语句,该语句指示用于列值的字符集。)

SET NAMES x这一说法相当于以下三种说法:

mysql> SET character_set_client = x;

mysql> SET character_set_results = x;

mysql> SET character_set_connection = x;

执行完此sql语句,随后由此Connection对象创建。Statement将被成功执行。

至此,问题已经完美地解决了,但我想到了一个新的问题:

jvm当虚拟机运行时,内存中的字符串将被占用。utf-16编码,ios中的emoji表达此用法4字节utf-8在中对存储的字符进行编码。java运行库是如何存储的?

所以,我找到了一个emoji字符(4字节的值为0xf0,0x9F,0x92,0x9c),进行了以下测试。

byte[] bytes = new byte[] { (byte) 0xf0, (byte) 0x9F, (byte) 0x92, (byte) 0x9c };
        String s = new String(bytes, Charset.forName("utf-8"));
        System.out.println("length:"+s.length());
        for (int i=0;i

执行结果如下:

从结果可以看出,unicode值(也叫codePoint代码点,稍后介绍API将被使用)更大0xffff只有一个角色,jvm内部占用2个char的长度4字节)存储。

所有大于0xffff所有的角色,都在UTF在编码表的辅助平面中(域辅助平台对应于基本平面,简称BMP)。所以呢,String中的某个char,是基面字,还是辅面字的一部分,也是很好的判断。如下所述java.lang.Character中的一些API:

在下面的描述中,代码点是字符。unicode值

Character中API

描述

isValidCodePoint(int codePoint):boolean

确定输入的码点是否有效,都属于。UTF定义平面的代码点有效。

isBmpCodePoint(int codePoint):boolean

确定输入码点是否属于基面,即:0x0000~0xffff

isSupplementaryCodePoint(int codePoint):boolean

确定输入码点是否属于辅助平面,即。>0xffff

isSurrogate(char ch):boolean

确定输入的字符是否为辅助平面字符的一部分。

获取String中字符的代码点也很容易调用。String.codePointAt(int index):int即可。

最后,关于unicode、UCS-2、UCS-4、UTF-8、UTF-16代码之间的关系,请读者百度公司。文章太多了,我就不在这里介绍了。

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门