不正确的字符串值;当试图插入UTF-8到MySQL通过JDBC?

这是我的连接设置:
Connection conn = DriverManager.getConnection(url + dbName + "?useUnicode=true&characterEncoding=utf-8", userName, password); < / p > 我得到以下错误时轮胎添加一行到表:
Incorrect string value: '\xF0\x90\x8D\x83\xF0\x90...' for column 'content' at row 1 < / p >

我插入数千条记录,当文本包含\xF0时,我总是得到这个错误(即不正确的字符串值总是以\xF0开始)。

列的排序规则是utf8_general_ci。

有什么问题吗?

507513 次浏览

包含\xF0的字符串就是使用UTF-8的编码为多个字节的字符

虽然你的排序规则被设置为utf8_general_ci,但我怀疑数据库、表甚至列都可能不同的字符编码。它们是独立设置。试一试:

ALTER TABLE database.table MODIFY COLUMN col VARCHAR(255)
CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;

将实际数据类型替换为VARCHAR(255)

MySQL的utf8只允许用UTF-8中3个字节表示的Unicode字符。这里有一个需要4个字节的字符:\xF0\x90\x8D\x83 (U+10343哥特式字母sauil)。

如果你有MySQL 5.5或更高版本,你可以将列编码从utf8改为utf8mb4。这种编码允许在UTF-8中存储占用4个字节的字符。

你可能还必须在MySQL配置文件中将服务器属性character_set_server设置为utf8mb4。似乎否则连接器/J默认为3字节Unicode:

例如,要在Connector/J中使用4字节UTF-8字符集,请使用character_set_server=utf8mb4配置MySQL服务器,并将characterEncoding排除在Connector/J连接字符串之外。Connector/J将自动检测UTF-8设置。

同样的问题,用utf8mb4保存数据需要确保:

  1. character_set_client, character_set_connection, character_set_resultsutf8mb4: character_set_clientcharacter_set_connection表示客户端发送语句的字符集,character_set_results表示服务器端向客户端返回查询结果的字符集。
    看到charset-connection。< / p >

  2. 表和列的编码是utf8mb4

对于JDBC,有两种解决方案:

解决方案一(需要重启MySQL):

  1. 修改my.cnf,并重新启动MySQL:

     [mysql]
    default-character-set=utf8mb4
    
    
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    

这可以确保数据库和character_set_client, character_set_connection, character_set_results默认为utf8mb4

  1. < p >启动MySQL

  2. 修改表和列编码为utf8mb4

  3. 停止在jdbc连接器中指定characterEncoding=UTF-8characterSetResults=UTF-8,因为这将覆盖character_set_clientcharacter_set_connectioncharacter_set_resultsutf8

解决方案二(不需要重启MySQL):

  1. 修改表和列编码为utf8mb4

  2. 在jdbc连接器中指定characterEncoding=UTF-8,因为jdbc连接器不支持utf8mb4

  3. 这样写你的sql语句(需要将allowMultiQueries=true添加到jdbc连接器):

     'SET NAMES utf8mb4;INSERT INTO Mytable ...';
    

这将确保到服务器的每个连接,character_set_client,character_set_connection,character_set_results都是utf8mb4
也可参见charset-connection.

这主要是由一些unicode字符引起的。对我来说,它是卢比的货币符号。

为了快速修复这个问题,我必须找出导致这个错误的字符。我把整个文本复制粘贴到一个文本编辑器中,比如vi,然后用一个文本替换掉麻烦的字符。

就我而言,我尝试了以上所有方法,但都没用。我非常确定,我的数据库如下所示。

mysql  Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using  EditLine wrapper


Connection id:      12
Current database:   xxx
Current user:       yo@localhost
SSL:            Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.17-0ubuntu0.16.04.1 (Ubuntu)
Protocol version:   10
Connection:     Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8
UNIX socket:        /var/run/mysqld/mysqld.sock
Uptime:         42 min 49 sec


Threads: 1  Questions: 372  Slow queries: 0  Opens: 166  Flush tables: 1  Open tables: 30  Queries per second avg: 0.144

所以,我在每个表中查找列字符集

show create table company;

原来列字符集是拉丁文。这就是为什么我无法将中文插入数据库。

 ALTER TABLE company CONVERT TO CHARACTER SET utf8;

这可能对你有帮助。:)

我想结合几篇文章来完整地回答这个问题,因为它看起来确实是几个步骤。

  1. 以上建议来自@madtracey

/etc/mysql/my.cnf/etc/mysql/mysql.conf.d/mysqld.cnf

[mysql]
default-character-set=utf8mb4


[mysqld_safe]
socket          = /var/run/mysqld/mysqld.sock
nice            = 0


[mysqld]
##
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

同样,根据上面的建议,所有jdbc连接都从它们中删除了__abc0和characterSetResults=UTF-8

在这个集合中,-Dfile.encoding=UTF-8似乎没有什么区别。

我仍然不能写入国际文本到db得到同样的失败,如上所述

现在使用how-to-convert-an-entire-mysql-database-characterset-and-collation-to-utf-8

更新你所有的db使用utf8mb4

ALTER DATABASE YOURDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

运行这个查询,它将为您提供需要调用的内容

SELECT CONCAT(
'ALTER TABLE ',  table_name, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;  ',
'ALTER TABLE ',  table_name, ' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;  ')
FROM information_schema.TABLES AS T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` AS C
WHERE C.collation_name = T.table_collation
AND T.table_schema = 'YOURDB'
AND
(C.CHARACTER_SET_NAME != 'utf8mb4'
OR
C.COLLATION_NAME not like 'utf8mb4%')

在编辑器中复制粘贴输出,当连接到正确的db时,将所有|替换为无post回mysql。

这就是我要做的一切,而且似乎对我很有效。而不是-Dfile.encoding=UTF-8没有启用,它看起来像预期的那样工作

E2A还有问题吗? 我当然在生产中,所以事实证明你确实需要检查上面所做的事情,因为它有时不工作,这里是原因和修复在这种情况下:

show create table user


`password` varchar(255) CHARACTER SET latin1 NOT NULL,
`username` varchar(255) CHARACTER SET latin1 NOT NULL,
你可以看到一些仍然是拉丁文 试图手动更新记录:

ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

让我们缩小范围:

mysql> ALTER TABLE user change username username varchar(255) CHARACTER SET utf8mb4 not NULL;
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
mysql> ALTER TABLE user change username username varchar(100) CHARACTER SET utf8mb4 not NULL;
Query OK, 5 rows affected (0.01 sec)

简而言之,为了让更新工作,我必须减小字段的大小。

现在当我跑步的时候:

mysql> ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0

都能正常工作

只做

ALTER TABLE `some_table`
CHARACTER SET = utf8 , COLLATE = utf8_general_ci ;


ALTER TABLE `some_table`
CHANGE COLUMN `description_with_latin_or_something` `description` TEXT CHARACTER SET 'utf8' NOT NULL ;

我在我的rails项目中遇到了同样的问题:

Incorrect string value: '\xF0\xA9\xB8\xBDs ...' for column 'subject' at row1
解决方案1:在保存到db之前,将字符串通过Base64.encode64(subject)转换为base64 并且在从db中获取数据后使用Base64.decode64(subject)

解决方案2:

< p >步骤1: 将主题列的字符集(和排序规则)更改为

ALTER TABLE t1 MODIFY
subject VARCHAR(255)
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

步骤2:在数据库中。yml使用

encoding :utf8mb4

我的解决方案是将列类型从varchar(255)更改为blob

如果您只想对一个字段应用更改,您可以尝试序列化该字段

class MyModel < ActiveRecord::Base
serialize :content


attr_accessible :content, :title
end

假设您正在使用phpmyadmin来解决此错误,请遵循以下步骤:

  1. phpMyAdmin
  2. your_table
  3. “结构”选项卡
  4. 将字段的Collation从latin1_swedish_ci(或其他什么)更改为utf8_general_ci

我的PLAY Java应用程序有这个问题。这是我对该异常的堆栈跟踪:

javax.persistence.PersistenceException: Error[Incorrect string value: '\xE0\xA6\xAC\xE0\xA6\xBE...' for column 'product_name' at row 1]
at io.ebean.config.dbplatform.SqlCodeTranslator.translate(SqlCodeTranslator.java:52)
at io.ebean.config.dbplatform.DatabasePlatform.translate(DatabasePlatform.java:192)
at io.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:83)
at io.ebeaninternal.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.java:49)
at io.ebeaninternal.server.core.PersistRequestBean.executeInsert(PersistRequestBean.java:1136)
at io.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:723)
at io.ebeaninternal.server.core.PersistRequestBean.executeNoBatch(PersistRequestBean.java:778)
at io.ebeaninternal.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:769)
at io.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:456)
at io.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:406)
at io.ebeaninternal.server.persist.DefaultPersister.save(DefaultPersister.java:393)
at io.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1602)
at io.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1594)
at io.ebean.Model.save(Model.java:190)
at models.Product.create(Product.java:147)
at controllers.PushData.xlsupload(PushData.java:67)
at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$40(Routes.scala:690)
at play.core.routing.HandlerInvokerFactory$$anon$3.resultCall(HandlerInvoker.scala:134)
at play.core.routing.HandlerInvokerFactory$$anon$3.resultCall(HandlerInvoker.scala:133)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$8$$anon$2$$anon$1.invocation(HandlerInvoker.scala:108)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:88)
at play.http.DefaultActionCreator$1.call(DefaultActionCreator.java:31)
at play.core.j.JavaAction.$anonfun$apply$8(JavaAction.scala:138)
at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:655)
at scala.util.Success.$anonfun$map$1(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map$1(Future.scala:289)
at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
at scala.concurrent.impl.CallbackRunnable.run$$$capture(Promise.scala:60)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala)
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:48)
at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:68)
at scala.concurrent.impl.Promise$KeptPromise$Kept.onComplete(Promise.scala:368)
at scala.concurrent.impl.Promise$KeptPromise$Kept.onComplete$(Promise.scala:367)
at scala.concurrent.impl.Promise$KeptPromise$Successful.onComplete(Promise.scala:375)
at scala.concurrent.impl.Promise.transform(Promise.scala:29)
at scala.concurrent.impl.Promise.transform$(Promise.scala:27)
at scala.concurrent.impl.Promise$KeptPromise$Successful.transform(Promise.scala:375)
at scala.concurrent.Future.map(Future.scala:289)
at scala.concurrent.Future.map$(Future.scala:289)
at scala.concurrent.impl.Promise$KeptPromise$Successful.map(Promise.scala:375)
at scala.concurrent.Future$.apply(Future.scala:655)
at play.core.j.JavaAction.apply(JavaAction.scala:138)
at play.api.mvc.Action.$anonfun$apply$2(Action.scala:96)
at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:304)
at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
at scala.concurrent.impl.CallbackRunnable.run$$$capture(Promise.scala:60)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala)
at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:91)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: java.sql.SQLException: Incorrect string value: '\xE0\xA6\xAC\xE0\xA6\xBE...' for column 'product_name' at row 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2734)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at io.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.java:82)
at io.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.java:122)
at io.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:73)
... 59 more

我想用io.Ebean保存一条记录。我通过使用utf8mb4排序规则重新创建我的数据库来修复它,并应用play evolution重新创建所有表,以便所有表都应该使用utf-8排序规则重新创建。

CREATE DATABASE inventory CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

您需要在元html和服务器alter表中设置utf8mb4,并将collation设置为utf8mb4

如果您正在创建一个新的MySQL表,您可以在创建时指定所有列的字符集,这为我解决了这个问题。

CREATE TABLE tablename (
<list-of-columns>
)
CHARSET SET utf8mb4 COLLATE utf8mb4_unicode_ci;

你可以阅读更多细节:https://dev.mysql.com/doc/refman/8.0/en/charset-column.html

这不是推荐的解决方案。但值得分享。因为我的项目是升级数据库从旧的Mysql到最新的(8).但我不能改变表结构,只有数据库配置(Mysql)。mysql服务器的解决方案。

测试Windows mysql 8.0.15 在mysql 配置搜索

sql模式= "…"

取消它。或者在我的例子中,只需输入/添加

sql模式= " NO_ENGINE_SUBSTITUTION "

为什么不推荐解决方案。因为如果你用拉丁语(我的情况)..数据插入成功,但没有插入内容(mysql没有响应错误!!)例如,你输入这样的信息

bla \ x12

它保存

Bla[](方块)

好吧. .对于我的问题…我可以把字段改为UTF8..但是有一个小问题。参见上面关于其他解决方案失败的答案,因为字没有插入,因为包含超过2个字节(cmiiw)..这个解决方案使您的插入数据变成方框。合理的是使用blob..你可以跳过我的回答。

另一个与此相关的测试是..在保存之前在代码上使用utf8_encode。我使用latin1,它是成功的(我没有使用sql模式)!与上面使用base64_encode回答相同。

我的建议是分析你的表格需求,并尝试从其他格式改为UTF8

提示:在AWS RDS上,你需要一个新的参数组用于你的MySQL DB的参数(而不是编辑my.cnf)

  • collation_connection: utf8mb4_unicode_ci
  • collation_database: utf8mb4_unicode_ci
  • collation_server: utf8mb4_unicode_ci
  • character_set_client: utf8mb4
  • character_set_connection: utf8mb4
  • character_set_database: utf8mb4
  • character_set_results: utf8mb4
  • character_set_server: utf8mb4

注意:character_set_system保持“utf8”

这些SQL命令只在会话中执行< em >不 WORK permanent :

set character_set_server = utf8mb4;
set collation_server = utf8mb4_unicode_ci;

我还必须删除并重新创建数据库的所有存储过程(以及函数),以便它们在utf8mb4的新字符集中执行。

运行:

SHOW PROCEDURE STATUS;

查看哪些过程没有更新到服务器的新的character_set_client、collation_connection和Database Collation值。

删除模式并使用utf8mb4字符集重新创建它解决了我的问题。

但是,需要注意的是,mysql连接器驱动程序版本必须高于5.1.47及以上。

在尝试了许多查询之后,终于成功了

ALTER TABLE
table_name
CHANGE column_name column_name
varchar(256)
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

如果您在java中面临类似的问题,并且没有灵活性来更改数据库的字符集和排序编码,那么这个答案是为您准备的。

你可以使用Emoji Java库(或类似的东西,如果你不使用java)来实现相同的功能。你可以 在保存/更新到数据库之前转换为别名 转换回Unicode后保存/更新/从数据库加载。主要的 好处是文本的可读性,即使编码后,因为 这个库只对表情符号的别名,而不是整个字符串

示例代码快照:

字符串/Unicode到别名(在保存/更新到DB之前)

String str = "An 😀awesome 😃string with a few 😉emojis!";
String result = EmojiParser.parseToAliases(str);
System.out.println(result);
// Prints:
// "An :grinning:awesome :smiley:string with a few :wink:emojis!"

Unicode/字符串的别名(保存/更新/从DB加载后)

String str = "An :grinning:awesome :smiley:string &#128516;with a few :wink:emojis!";
String result = EmojiParser.parseToUnicode(str);
System.out.println(result);
// Prints:
// "An 😀awesome 😃string 😄with a few 😉emojis!"
你可以使用@PrePersist, @PreUpdate, @PostPersist, @PostUpdate, @PostLoad在实体本身做别名和unicode转换如果