尝试通过JDBC将UTF-8插入MySQL时,"字符串值不正确"?

Lio*_*ior 201 mysql jdbc utf-8 utf8mb4

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

当tyring为表添加一行时,我收到以下错误:
Incorrect string value: '\xF0\x90\x8D\x83\xF0\x90...' for column 'content' at row 1

我正在插入数千条记录,当文本包含\ xF0时,我总是会收到此错误(即错误的字符串值始终以\ xF0开头).

该列的排序规则为utf8_general_ci.

可能是什么问题呢?

Jon*_*oni 291

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,否则:

例如,要使用带有Connector/J的4字节UTF-8字符集character_set_server=utf8mb4,请characterEncoding使用Connector/J连接字符串配置MySQL服务器.然后,Connector/J将自动检测UTF-8设置.

  • 有一个奇怪的选择,utf8真正意味着"可以用3个字节表示的UTF8的子集". (133认同)
  • #对于每个数据库:ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; #对于每个表:ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; #对于每列:ALTER TABLE table_name CHANGE column_name column_name VARCHAR(191)CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; (19认同)
  • 奇怪的是UTF-8不是UTF-8,直到它被更新为UTF-8 (12认同)
  • `character_encoding_server`不是有效的MySQL配置变量名.我试图将`character_set_server`设置为`utf8mb4`,除了单独的列,但它没有改变任何东西. (4认同)
  • 因此,您建议具有3个(三个)字节的UTF-8无法存储带小标题(ñ)的拉丁文小写字母N,而我们需要4个(四个)字节才能正确拼写“España”?真?会比这更有效率吗?除了AZ和0-9以及3个字节,我们还能存储什么。 (3认同)
  • 当我将数据库更改为 utf8mb4 并且停止指定 characterEncoding=UTF-8&characterSetResults=UTF-8 时,我还必须执行另外一个步骤。这实际上阻止了对 utf8mb4 的正确处理。 (2认同)
  • 请至少停止调用`utf8mb3``utf` (2认同)

Eri*_* J. 84

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

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

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

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

  • 实际上尝试过,没有用.如果这很重要,列的数据类型是LONGTEXT btw. (4认同)
  • 我建议你把重点放在**“数据库、表甚至列的字符编码可能不同”**。这是最重要的事情。 (3认同)

小智 52

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

  1. character_set_client, character_set_connection, character_set_resultsutf8mb4:character_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
    
    Run Code Online (Sandbox Code Playgroud)

这可以确保数据库character_set_client, character_set_connection, character_set_resultsutf8mb4在默认情况下.

  1. 重启MySQL

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

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

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

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

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

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

    'SET NAMES utf8mb4;INSERT INTO Mytable ...';
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 对于我来说,改变数据库,表格和字段编码是第3点的关键:'SET NAMES utf8mb4; INSERT INTO Mytable ...'; (3认同)

Vin*_*yon 13

我想结合几篇文章来完整回答这个问题,因为它似乎只是几个步骤.

  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
Run Code Online (Sandbox Code Playgroud)

再从上面所有的JDBC连接的建议有characterEncoding=UTF-8,并characterSetResults=UTF-8从中取出

这套装-Dfile.encoding=UTF-8似乎没有任何区别.

我仍然无法将国际文本写入数据库获得与上述相同的失败

现在使用这个how-to-convert-an-whole-mysql-database-characterset-and-collat​​ion-to-utf-8

更新要使用的所有数据库 utf8mb4

ALTER DATABASE YOURDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Run Code Online (Sandbox Code Playgroud)

运行此查询,为您提供需要响铃的内容

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%')
Run Code Online (Sandbox Code Playgroud)

在编辑器中复制粘贴输出替换所有| 连接到正确的数据库时没有回发到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,
Run Code Online (Sandbox Code Playgroud)

您可以看到一些仍在拉丁尝试手动更新记录:

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

所以让我们缩小范围:

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)
Run Code Online (Sandbox Code Playgroud)

简而言之,我必须减小该字段的大小才能使更新生效.

现在我跑的时候:

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

一切正常


小智 7

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

Incorrect string value: '\xF0\xA9\xB8\xBDs ...' for column 'subject' at row1
Run Code Online (Sandbox Code Playgroud)

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

解决方案2:

步骤 1:通过以下方式更改主题列的字符集(和排序规则)

ALTER TABLE t1 MODIFY
subject VARCHAR(255)
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;
Run Code Online (Sandbox Code Playgroud)

第 2 步:在 database.yml 中使用

encoding :utf8mb4
Run Code Online (Sandbox Code Playgroud)


cra*_*age 5

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

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
Run Code Online (Sandbox Code Playgroud)

因此,我在每个表中查找列字符集

show create table company;
Run Code Online (Sandbox Code Playgroud)

原来列字符集是拉丁语。因此,我无法将中文插入数据库。

 ALTER TABLE company CONVERT TO CHARACTER SET utf8;
Run Code Online (Sandbox Code Playgroud)

那可能对您有帮助。:)


sha*_*eef 5

做就是了

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 ;
Run Code Online (Sandbox Code Playgroud)


Teo*_*ila 5

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

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

  • 无效,您假设他使用phpMyAdmin。 (3认同)

小智 5

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

在Windows mysql 8.0.15上测试 mysql配置搜索

sql-模式=“......”

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

sql-mode =“NO_ENGINE_SUBSTITUTION”

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

bla\x12

它保存

bla[](框)

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

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

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