尝试通过JDBC将UTF-8插入MySQL时出现“字符串值错误”的问题?


228

这是我的连接设置方式:
Connection conn = DriverManager.getConnection(url + dbName + "?useUnicode=true&characterEncoding=utf-8", userName, password);

尝试在表中添加行时出现以下错误:
Incorrect string value: '\xF0\x90\x8D\x83\xF0\x90...' for column 'content' at row 1

我正在插入数千条记录,并且当文本包含\ xF0时,总是会出现此错误(即,不正确的字符串值始终以\ xF0开头)。

该列的排序规则是utf8_general_ci。

可能是什么问题呢?


那应该是带小标题的拉丁文小写字母N(ñ)。
andreszs

对于其他遇到此问题的人,您可以尝试:在数据库上:ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -它将解决“从现在开始”创建的表。不适用于EXIST表。对于他们,您需要执行以下操作:ALTER TABLE table_name转换为字符集utf8mb4 COLLUT utf8mb4_unicode_ci; 来源- digitalocean.com/community/questions/...
lingar

Answers:


321

MySQL的utf8许可仅允许使用UTF-8中的3个字节表示的Unicode字符。在这里,您需要一个需要4个字节的字符:\ xF0 \ x90 \ x8D \ x83(U + 10343 GOTHIC LETTER SAUIL)。

如果您使用的是MySQL 5.5或更高版本,则可以将列编码从更改utf8utf8mb4。此编码允许存储在UTF-8中占用4个字节的字符。

您可能还需要服务器属性设置character_set_serverutf8mb4MySQL的配置文件中 似乎Connector / J默认为3字节Unicode,否则

例如,要将4字节UTF-8字符集用于Connector / J,请使用配置MySQL服务器character_set_server=utf8mb4,并保留characterEncodingConnector / J连接字符串。然后,Connector / J将自动检测UTF-8设置。


151
拥有utf8的奇怪选择实际上意味着“可以用3个字节表示的UTF8的子集”。
Eric J.

4
character_encoding_server不是有效的MySQL配置变量名称。除了单独的列,我尝试设置character_set_serverutf8mb4,但是它没有任何改变。
Romain Paulus 2014年

20
#对于每个数据库:ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; #对于每个表:ALTER TABLE table_name转换为字符集utf8mb4 COLLATE utf8mb4_unicode_ci; #对于每个列:ALTER TABLE table_name更改column_name column_name VARCHAR(191)字符集utf8mb4 COLLATE utf8mb4_unicode_ci;
iKing 2015年

14
奇怪的是,在将UTF-8更新为UTF-8之前,它不是UTF-8
Klors

3
因此,您建议具有3(三个)字节的UTF-8无法存储带小标题(ñ)的拉丁文小写字母N,而我们需要4(四个)字节来正确拼写“España”吗?真?会比这更有效率吗?我们可以存储什么,除了AZ和0-9三字节的话..
andreszs

94

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

尽管您的排序规则设置为utf8_general_ci,但我怀疑数据库,表甚至列的字符编码可能不同。它们是独立设置。尝试:

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

用您的实际数据类型替换VARCHAR(255)


4
实际尝试过,没有用。如果这很重要,则列的数据类型为LONGTEXT btw。
Lior 2012年

1
您的应用程序是Java语言的吗?尝试使用file-encoding指定UTF-8 的参数调用Java ,例如,java -Dfile.encoding=UTF-8或在Tomcat(等)配置文件中添加适当的开关。
埃里克·J.

1
我建议您强调“数据库,表甚至列的字符编码可能不同”。那是最重要的。
Gellie Ann

您还必须使用CHARACTER SET utf8 COLLATE utf8_general_ci更改表,然后更改列CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci
Shobhit Sharma

68

遇到相同的问题,要utf8mb4确保需要保存数据:

  1. character_set_client, character_set_connection, character_set_resultsutf8mb4character_set_clientcharacter_set_connection指示字符集,其中的语句由客户端发送,character_set_results指示字符集的服务器查询结果返回给客户端。
    请参见charset-connection

  2. 表和列的编码是 utf8mb4

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

解决方案1(需要重启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_resultsutf8mb4在默认情况下。

  1. 重启MySQL

  2. 将表和列编码更改为 utf8mb4

  3. STOP指定characterEncoding=UTF-8characterSetResults=UTF-8在JDBC连接器,会导致此将覆盖character_set_clientcharacter_set_connectioncharacter_set_resultsutf8

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

  1. 将表和列编码更改为 utf8mb4

  2. characterEncoding=UTF-8在jdbc连接器中指定,因为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


3
对于更改数据库,表和字段编码而言,第3点对我来说是至关重要的:'SET NAMES utf8mb4; INSERT INTO Mytable ...';
kbbucks

第3点对我也有用,因为我的表编码已经设置为utf8mb4。
纳爵士(Sir_Faenor)'17年

表编码只是默认设置。将列编码更改为utf8mb4就足够了。
瑞克·詹姆斯

第二种方法应该有选择地使用,即永远不要应用于SELECT查询,因为它set names utf8mb4; select ... from ...永远不会产生a ResultSet而是导致ResultSet is from UPDATE. No Data.错误。
巴斯

解决方案2,正好相符。当我尝试通过联系表格插入西里尔文字时,1帮助了我。
Vadim Anisimov

15

我想结合几个帖子来对此做一个完整的答案,因为这似乎只是几个步骤。

  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连接了characterEncoding=UTF-8characterSetResults=UTF-8从中取出

与此设置-Dfile.encoding=UTF-8似乎没有什么区别。

我仍然无法将国际文本写入db,得到与上述相同的失败

现在使用此方法来转换整个MySQL数据库字符集和归类到utf-8

更新所有数据库以使用 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%')

在编辑器中复制粘贴输出替换所有| 连接到正确的数据库时,没有任何内容发回到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命令会将所有VARCHAR字段的内容转换为有效的,真正的UTF8编码的字符串吗?我问是因为我在将我的LATIN1字段转换为UTF8时遇到问题,特别是在找到ñ字符时,由于字符串值不正确(错误1366),转换直接失败。
andreszs

如果您ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;在我最后一次运行此命令时的意思足够奇怪,那么所有字段都不再定义字符集。因此,上面的密码变成了passwordvarchar(255)NOT NULL(与编码无关)。这意味着最后一个命令只必须已经使mysql查找实际的表定义是什么,并且因为现在该表默认情况下该字段不再需要它了-我认为它们保留了字符集,这仅仅是因为在转储整个表更新期间它无法更新它,因此它处于该状态
VH

7

就我而言,我尝试了上述所有操作,但没有任何效果。我很确定,我的数据库如下所示。

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;

那可能对您有帮助。:)


7

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

Incorrect string value: '\xF0\xA9\xB8\xBDs ...' for column 'subject' at row1

解决方案1:在保存到db之前Base64.encode64(subject) 以及从db提取使用后将字符串转换为base64 Base64.decode64(subject)

解决方案2:

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

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

步骤2:在database.yml中使用

encoding :utf8mb4

4

做就是了

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 ;

如果我有一堆要在数据库中更改的表怎么办?如果所有的存储引擎都不同(innodb等)怎么办?
Yannis Dran

4

假设您正在使用phpmyadmin解决此错误,请按照下列步骤操作:

  1. phpMyAdmin
  2. your_table
  3. “结构选项卡”
  4. 将您的字段的排序规则从latin1_swedish_ci(或任何形式)更改为utf8_general_ci

5
无效,您假设他使用phpMyAdmin。
ShaH

不起作用......并且排序规则更改为“操作”而非结构
Olorunfemi Ajibulu

@OlorunfemiAjibulu是的,您也可以在“结构”中进行更改。对于这里的某些人来说,它起作用了
Teo Mihaila

@TeoMihaila也许是版本控制。
Olorunfemi Ajibulu

3

它主要是由于某些Unicode字符引起的。就我而言,它是卢比的货币符号。

为了快速解决此问题,我必须找出导致此错误的字符。我在像vi这样的文本编辑器中复制并粘贴了整个文本,并用一个文本替换了麻烦的字符。


3
该OP提到,有一个一千记录被插入....
Gellie安

3

我的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;

2

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

class MyModel < ActiveRecord::Base
  serialize :content

  attr_accessible :content, :title
end


2

这不是推荐的解决方案。但是值得分享。由于我的项目是将DBMS从旧的Mysql升级到最新的(8)。但是我不能更改表结构,只能更改DBMS配置(mysql)。mysql服务器的解决方案。

Windows mysql 8.0.15 上测试mysql config搜索

sql-mode =“ .....”

取消注释。或者在我的情况下,只需键入/添加

sql-mode =“ NO_ENGINE_SUBSTITUTION”

为什么不推荐解决方案。因为如果您使用latin1(我的情况)..数据会成功插入,但不会成功插入内容(mysql无法响应!!)。例如您键入信息

bla \ x12

它保存

bla [](框)

好的..对于我的问题..我可以将字段更改为UTF8 ..但是有一个小问题..关于其他解决方案,请参见上述答案失败,因为未插入该字,因为包含的字节数超过2个字节(cmiiw)。解决方案使您的插入数据成为盒子。合理的是使用blob ..,您可以跳过我的回答。

与此相关的另一个测试是.. 在保存之前在代码上使用utf8_encode。我在latin1上使用,但成功了(我没有使用sql-mode)!与上述答案相同,使用base64_encode

我建议分析您的表要求,并尝试从其他格式更改为UTF8


在我的settings.py(Django项目)中,我更改为sql-mode =“ NO_ENGINE_SUBSTITUTION”。工作正常
Taciano Morais Silva

1

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



1

提示:在AWS RDS上,您需要一个带有参数的MySQL数据库新参数组(而不是编辑my.cnf)

  • collat​​ion_connection:utf8mb4_unicode_ci
  • collat​​ion_database:utf8mb4_unicode_ci
  • collat​​ion_server:utf8mb4_unicode_ci
  • character_set_client:utf8mb4
  • character_set_connection:utf8mb4
  • 字符集数据库:utf8mb4
  • character_set_results:utf8mb4
  • 字符集服务器:utf8mb4

注意:character_set_system保持为“ utf8”

这些SQL命令不能永久起作用 -仅在会话中:

set character_set_server = utf8mb4;
set collation_server = utf8mb4_unicode_ci;

0

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

跑:

SHOW PROCEDURE STATUS;

…查看哪些过程尚未更新为服务器的新character_set_client,collat​​ion_connection和Database Collat​​ion值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.