首页 > 解决方案 > Java / Postgres / Mybatis - 编码“UTF8”的无效字节序列:0xe3 0xa1 0x54

问题描述

在我们的应用服务器上,DevOps 团队在 Postgres (9.4) DB 中使用 SQL_ASCII 编码。

第 3 方应用程序正在将姓氏插入到 Employee 表中并带有重音字符,例如 Núñez

我的 Java (8) 应用程序是使用 Mybatis (3.2.4) 的 Spring (4.3.15) WebApp

当我的应用程序从 SQL_ASCII 数据库中读取此类姓氏时,我得到:

org.postgresql.util.PSQLException:错误:用于编码“UTF8”的无效字节序列:org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182) 处 org.postgresql.core.v3 处的 0xe3 0xa1 0x54。 QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911) 在 org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173) 在 org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:616) 在 org.postgresql .jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:466) at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:459) at org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:93 ) 在 org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:93) 在 jdk.internal.reflect.GeneratedMethodAccessor78.invoke(Unknown Source) 在 java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.base/java.lang.reflect.Method。在 com.sun.proxy.$Proxy98.execute(未知来源)的 org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:55) 调用(Method.java:566)

如果我尝试通过以下方式更改 client_encoding:

SET client_encoding = 'SQL_ASCII';

然后我得到错误:

org.postgresql.util.PSQLException:服务器的 client_encoding 参数已更改为 LATIN1。JDBC 驱动程序要求 client_encoding 为 UTF8 才能正确操作。在 org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1950)

我怎样才能“安全地”从数据库中读取这些字符?

标签: javapostgresqlutf-8

解决方案


allowEncodingChanges=true

您可以尝试allowEncodingChanges=true在 JDBC 连接 URL 中进行设置吗?(还有characterEncoding

allowEncodingChanges = 布尔值

使用 V3 协议时,驱动程序会监控最终用户不应触及的某些服务器配置参数的变化。client_encoding 设置由驱动程序设置,不应更改。如果驱动程序检测到更改,它将中止连接。但是,这种行为有一个合法的例外,即对驻留在服务器文件系统上的文件使用 COPY 命令。指定此文件编码的唯一方法是更改​​ client_encoding 设置。JDBC 团队认为这是 COPY 命令的失败,并希望将来提供另一种指定编码的方法,但现在有这个 URL 参数。仅当您需要在进行复制时覆盖客户端编码时才启用此选项。

参考:第 3 章。初始化驱动程序

错误消息中的字节为1110 0011, 1010 0001,0101 0100

如果存储的数据以 编码ISO-8859-1,则为ã, ¡, T

当这个字节流被读取为UTF-8时,第一个字节中的1110MSB表示一个3UTF-8 字节字符(自计数)。

所以接下来的 2 个字节应该以10MSB开头。但是第 3字节以01MSB开头

默认情况下,JDBC驱动程序正在解码此流UTF-8并在无效字节流上失败。

假设第三个字节以10MSB开头,则代码可以正常工作,但它可能会错误地将所有这些3字节映射到 a single Unicode code point(假设原始编码不是UTF-8并且相应的 unicode 代码点具有有效的字符表示)。


推荐阅读