java.sql.SQLException: Incorrect string value: '\xF0\x9F\x91\xBD\xF0\x9F...'

I have the following string value: "walmart obama 👽💔"

I am using MySQL and Java.

I am getting the following exception: `java.sql.SQLException: Incorrect string value: '\xF0\x9F\x91\xBD\xF0\x9F...'

Here is the variable I am trying to insert into:

var1 varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL`

My Java code that is trying to insert "walmart obama 👽💔" is a preparedStatement. So I am using the setString() method.

It looks like the problem is the encoding of the values 👽💔. How can I fix this? Previously I was using Derby SQL and the values 👽💔 just ended up being two sqaures (I think this is the representation of the null character)

All help is greatly appreciated!

139022 次浏览

将代码行 useUnicode=true&characterEncoding=UTF-8追加到 jdbcurl。

在您的情况下,数据不是使用 UTF-8编码发送的。

我猜 MySQL 不相信这是有效的 UTF8文本。我尝试在一个具有相同列定义的测试表上插入(MySQL 客户端连接也是 UTF8) ,尽管它插入了,但是我用 MySQL CLI 客户端和 JDBC 检索到的数据并没有正确地检索到值。为了确保 UTF8正确工作,我插入了一个“ ö”而不是“ o”代表奥巴马:

johan@maiden:~$ mysql -vvv test < insert.sql
--------------
insert into utf8_test values(_utf8 "walmart öbama 👽💔")
--------------


Query OK, 1 row affected, 1 warning (0.12 sec)


johan@maiden:~$ file insert.sql
insert.sql: UTF-8 Unicode text

用来测试的小型 java 应用程序:

package test.sql;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;


public class Test
{


public static void main(String[] args)
{
System.out.println("test string=" + "walmart öbama 👽💔");
String url = "jdbc:mysql://hostname/test?useUnicode=true&characterEncoding=UTF-8";
try
{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection c = DriverManager.getConnection(url, "username", "password");
PreparedStatement p = c.prepareStatement("select * from utf8_test");
p.execute();
ResultSet rs = p.getResultSet();
while (!rs.isLast())
{
rs.next();
String retrieved = rs.getString(1);
System.out.println("retrieved=\"" + retrieved + "\"");


}
}
catch (Exception e)
{
e.printStackTrace();
}
}


}

产出:

johan@appel:~/workspaces/java/javatest/bin$ java test.sql.Test
test string=walmart öbama 👽💔
retrieved="walmart öbama "

另外,我已经尝试使用 JDBC 连接插入相同的代码,它抛出的异常与您正在获得的异常相同。 我相信这是一个 MySQL 错误。也许已经有一个关于这种情况的错误报告..。

你有的是 EXTRATERRESTRIAL ALIEN (U+1F47D)BROKEN HEART (U+1F494) 不在基本的多语言平面上。它们甚至不能在 java 中表示为一个字符 "👽💔".length() == 4。它们绝对不是空字符,如果不使用支持它们的字体,就会看到正方形。

MySQL's utf8 only supports basic multilingual plane, and you need to use utf8mb4 instead:

对于补充字符,utf8根本不能存储字符, 而 utf8mb4需要四个字节来存储它 中没有任何补充字符 Utf8列,则不必担心转换字符或 从旧版本的 MySQL 升级 utf8数据时丢失数据。

因此,为了支持这些字符,MySQL 需要5.5 + ,并且在任何地方都需要使用 utf8mb4。连接编码需要是 utf8mb4,字符集需要是 utf8mb4,聚合需要是 utf8mb4。对于 java 来说,它仍然只是 "utf-8",但是 MySQL 需要一个区别。

我不知道你在使用什么驱动程序,但是一个驱动程序不可知的设置连接字符集的方法是发送查询:

SET NAMES 'utf8mb4'

就在建立联系之后。

参见连接器/J :

14.14: How can I use 4-byte UTF8, utf8mb4 with Connector/J?

使用4字节 UTF8和 Connector/J 配置 MySQL 服务器 character_set_server=utf8mb4. Connector/J will then use that setting 只要在连接中设置了字符编码 没有 字符串 。这等效于字符集的自动检测。

也可以调整列和数据库:

var1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL

同样,您的 MySQL 版本需要相对最新的 utf8mb4支持。

Weirdly, I found that REMOVING &characterEncoding=UTF-8 from the JDBC url did the trick for me with similar issues.

基于我的财产,

jdbc_url=jdbc:mysql://localhost:3306/dbName?useUnicode=true

I think this supports what @Esailija has said above, i.e. my MySQL, which is indeed 5.5, is figuring out its own favorite flavor of UTF-8 encoding.

(注意,我还在 Java 代码中将读取的 InputStream指定为 UTF-8,这可能不会造成损害) ..。

我是怎么解决我的问题的。

是的

?useUnicode=true&amp;characterEncoding=UTF-8

在我的 hibernate jdbc 连接 url 中,我将字符串数据类型更改为 database 中的 longtext,这在之前是 varchar。

我也遇到了同样的问题,在仔细检查了所有字符集并发现它们都没问题之后,我意识到我在类中被窃听的属性被注释为@Column 而不是@JoinColumn (javax.presency; hibernate) ,它正在破坏一切。

我遇到了同样的问题,并通过将每个列的 校对设置为 Utf8 _ general _ ci来解决这个问题。

总之,要保存需要4个字节的符号,需要更新 utf8mb4的字符集和排序规则:

  1. 数据库表/列: alter table <some_table> convert to character set utf8mb4 collate utf8mb4_unicode_ci
  2. 数据库服务器连接()

在我针对 # 2的开发环境中,我更喜欢在启动服务器时在命令行上设置参数: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


btw, pay attention to 连接器/J 行为 with SET NAMES 'utf8mb4':

不要使用 Connector/J 发出查询集名称,因为驱动程序不会检测到字符集已经更改,并将继续使用在初始连接设置期间检测到的字符集。

并避免在连接 URL 中设置 characterEncoding参数,因为它将覆盖已配置的服务器编码:

若要覆盖客户端上自动检测到的编码,请使用用于连接到服务器的 URL 中的 properties Encoding 属性。

执行

show VARIABLES like "%char%”;

如果不是 utf8mb4,则查找字符集服务器。

放到你的 my.cnf 里

vim /etc/my.cnf

加一行

character_set_server = utf8mb4

最后重启 mysql

此外,数据类型还可以使用 varchar 或 text 的 blob 安装。

这个设置 useOldUTF8Behavior = true 对我来说很好用。它没有给出不正确的字符串错误,但是它将特殊字符(如 ó)转换为多个字符并保存在数据库中。

为了避免这种情况,我从 JDBC 参数中删除了这个属性,而是将列的数据类型转换为 BLOB。效果很好。