UTF8mb4 unicode 破坏 MariaDB JDBC 驱动程序

Posted

技术标签:

【中文标题】UTF8mb4 unicode 破坏 MariaDB JDBC 驱动程序【英文标题】:UTF8mb4 unicode breaking MariaDB JDBC driver 【发布时间】:2020-11-23 17:53:23 【问题描述】:

我有一些包含 unicode 字符的产品名称

⚠️????请阅读!可工作的柯达 DC215 变焦 1.0MP 数码相机 - 英国 卖家

heidiSQL 中的查询显示它很好

我今天早上从 mysql 迁移过来设置了新的 MariaDB,但是当使用 MariaDB JDBC 通过 ColdFusion 查询检索记录时,我得到了

java.lang.StringIndexOutOfBoundsException: begin 0, end 80, length 74
    at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3410)
    at java.base/java.lang.String.substring(String.java:1883)
    at org.mariadb.jdbc.internal.com.read.resultset.rowprotocol.TextRowProtocol.getInternalString(TextRowProtocol.java:238)
    at org.mariadb.jdbc.internal.com.read.resultset.SelectResultSet.getString(SelectResultSet.java:948)

productname 字段排序规则是utf8mb4_unicode_520_ci,我尝试了几个选项。我已经尝试在表和数据库级别进行设置。

ColdFusion 管理中的 JDBC 连接字符串是jdbc:mysql://localhost:3307/usedlens?useUnicode=true&characterEncoding=UTF-8

我注意到从一开始就使用 MariaDB 的实时生产数据库我没有这个问题,但默认字符集是 latin1,并且与数据库相同的记录是

????请阅读!可使用的柯达 DC215 变焦 1.0MP 数码相机 - 英国卖家

【问题讨论】:

见***.com/questions/38363566/…中的“问号” 是否正好有 4 个问号?我希望这 2 个表情符号有 10 个:十六进制:E29AA0 EFB88F F09F93B7 @RickJames 我照原样复制了文本,所以是的 4 ????,它与在 prod 上作为 dev 导入的产品相同。顺便说一句,如果我在我的数据库处理它们之前没有说清楚,请参阅添加的屏幕截图,这只是 Coldfusion 使用的 jdbc 引发了错误。 我没用过MariaDB,但你不应该指定characterEncoding=utf8mb4吗? 仅供参考:我将 CF2016 与 Microsoft JDBC SQL 驱动程序一起使用,并且 NVARCHAR 字段和表情符号已正确存储(使用默认拉丁排序规则)。我们还在同一列中支持多种外语,并且没有任何查询问题。我想知道这是否是一个严格的 JDBC 问题。 【参考方案1】:

以下是我们如何去除高位 ASCII 字符,同时保留任何可能被挽救的字符:

string function ASCIINormalize(string inputString="")
    return createObject( 'java', 'java.text.Normalizer' ).normalize( javacast("string", arguments.inputString) , createObject( 'java', 'java.text.Normalizer$Form' ).valueOf('NFD') ).replaceAll('\pInCombiningDiacriticalMarks+','').replaceAll('[^\pASCII]+','');


productname = ASCIINormalize(productname);

/*
Comparisons using java UDF versus reReplace regex:

"ABC   Café ’test"  (note: High ASCII non-normal whitespace characters used.)
   ASCIINormalize = "ABC Cafe test"
   reReplace = "ABC Caf test"

"čeština"
   ASCIINormalize = "cestina"
   reReplace = "etina"

"Häuser Bäume Höfe Gärten"
   ASCIINormalize = "Hauser Baume Hofe Garten"
   reReplace = "Huser Bume Hfe Grten"
*/

【讨论】:

注意:以上解决方案来自***.com/a/11642205/693068,我还建议使用名为 JUnidecode 的第三方 java 库。【参考方案2】:

这是由于构成表情符号的一系列高位 ASCII 字符造成的。在将 MSSQL 数据导出到 UTF-8 文件以使用 3rd 方工具转换为 Excel 时,我遇到了类似的问题。在这种情况下,数据库和文件是正确的,但第 3 方工具遇到表情符号时会崩溃。

我们解决此问题的方法是将表情符号转换为其别名,这样信息就不会在此过程中丢失。 (如果你去掉高位 ASCII 字符,你可能会丢失一些上下文。)为了清理表情符号以使用别名,我写了这个 ColdFusion cf-emoji-java (CFC) 以利用 emoji-java (JAR 文件) 将表情符号转换为它们的 ASCII7 安全别名.

emojijava = new emojijava();
emojijava.parseToAliases('I like ?');   // I like :pizza:

【讨论】:

删除表情符号可能是我唯一的选择,谢谢。但是正如您在添加的屏幕截图中看到的那样,数据库确实可以很好地处理它们,只是 ColdFusion 中的 JDBC 驱动程序引发了错误,我原以为它已经通过某处的正确配置解决了。 表情符号对于产品领域没有意义。如果您期望的文本应该是 ASCII7,您可以完全去除它们。如果这些是用户 cmets,则可能会丢失某些上下文或表达式,具体取决于表情符号的使用方式。【参考方案3】:

因为……

我并不是真正从事支持表情符号的业务 我的数据只是在可预见的未来针对英国、欧洲和美国的产品名称 我不想在生产中遇到同样的麻烦(已经默认为 latin1_swedish_ci)

我决定……

匹配生产,所以我在

的帮助下将数据库、表和字段设置为 latin1_swedish_ci

How to change the CHARACTER SET (and COLLATION) throughout a database?

并去除产品名称中的非 ASCII 字符

== 编辑不要这样做,它会删除太多有用的字符==

<cfset productname = reReplace(productname, "[^\x20-\x7E]", "", "ALL")>

【讨论】:

以上是关于UTF8mb4 unicode 破坏 MariaDB JDBC 驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 数据库 - 将字符集和排序规则转换为 utf8mb4 和 utf8mb4_unicode_ci?

MySQL数据库 - 将characterset和collat ion转换为utf8mb4和utf8mb4_unicode_ci?

MySQL Workbench 不考虑配置的字符集 utf8mb4

工作中使用的utf8与utf8mb4记录

utf8mb4和utf8有啥区别

浅谈MySQL中utf8和utf8mb4的区别