当前位置:网站首页>[MySQL] character set utf8mb4 cannot store the record of expression stepping on the pit
[MySQL] character set utf8mb4 cannot store the record of expression stepping on the pit
2022-07-24 02:02:00 【morris131】
The phenomenon
The character set on the field has priority over the character set of the table , The character set of the table takes precedence over the character set of the database , Theoretically, as long as the character set of the table is utf8mb4 Can store expressions , Is that really the case ?
MySQL The character set of the data table has been set to utf8mb4, But by JDBC Write... To the database 4 Bytes of emoji Expression times wrong , But through direct use SQL Statement inserts this... On the command line 4 Bytes of emoji The expression was successful .
Examples are as follows :
Table structure :
CREATE TABLE `user_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(11) NOT NULL,
`age` int(4) DEFAULT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
JDBC write in :
User user = new User();
user.setName("\uD83D\uDC8B");
user.setAge(18);
userMapper.insertUser(user);
The error results are as follows :
org.springframework.jdbc.UncategorizedSQLException:
### Error updating database. Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1
### The error may involve com.wakzz.database.persistence.UserMapper.insertUser-Inline
### The error occurred while setting parameters
### SQL: insert into user_info (name, age) values (?, ? )
### Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1
; uncategorized SQLException; SQL state [HY000]; error code [1366]; Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1; nested exception is java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:89)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy81.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:58)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy92.insertUser(Unknown Source)
Command line write succeeded :
mysql> insert into user_info (name,age) values ('',18);
Query OK, 1 row affected
The reason for the error
reason :JDBC It will automatically detect MySQL Server side character_set_server Value , Automatic execution SET NAMES Command sets the character set encoding of the entire connection , Its purpose is to automatically detect the character set encoding configuration of the server and reduce JDBC The character set encoding configuration of the client . If MySQL Server side character_set_server The value of is utf8, that JDBC The encoding of the connected character set will be set to utf8, In this way, even if the character set of the table is utf8mb4 It's also impossible to store expressions .
Official statement :https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1-13.html

see JDBC Source code discovery :
// realJavaEncoding by url It is specified in characterEncoding Value
if (realJavaEncoding.equalsIgnoreCase("UTF-8") || realJavaEncoding.equalsIgnoreCase("UTF8")) {
// charset names are case-sensitive
// take MySQL Server side character_set_server
boolean useutf8mb4 = CharsetMapping.UTF8MB4_INDEXES.contains(this.session.getServerDefaultCollationIndex());
if (!this.useOldUTF8Behavior.getValue()) {
if (dontCheckServerMatch || !this.session.characterSetNamesMatches("utf8") || (!this.session.characterSetNamesMatches("utf8mb4"))) {
// perform set names xxx
execSQL(null, "SET NAMES " + (useutf8mb4 ? "utf8mb4" : "utf8"), -1, null, false, this.database, null, false);
this.session.getServerVariables().put("character_set_client", useutf8mb4 ? "utf8mb4" : "utf8");
this.session.getServerVariables().put("character_set_connection", useutf8mb4 ? "utf8mb4" : "utf8");
}
} else {
execSQL(null, "SET NAMES latin1", -1, null, false, this.database, null, false);
this.session.getServerVariables().put("character_set_client", "latin1");
this.session.getServerVariables().put("character_set_connection", "latin1");
}
this.characterEncoding.setValue(realJavaEncoding);
}
In obtaining mysql After the server parameter of , Parse character set encoding :
- When character_set_server by utf8 when , perform SET NAMES utf8
- When character_set_server by utf8mb4 when , perform SET NAMES utf8mb4
Test on the command line SET NAMES It is found that even if the character set of the database table is utf8mb4 when , If implemented SET NAMES utf8 It can also lead to 4 Byte character writing mysql Failure . Successfully reproduced JDBC write in emoji Write exception problem .
mysql> SET NAMES utf8;
Query OK, 0 rows affected
mysql> insert into user_info (name,age) values ('',18);
1366 - Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1
mysql> SET NAMES utf8mb4;
Query OK, 0 rows affected
mysql> insert into user_info (name,age) values ('',18);
Query OK, 1 row affected
terms of settlement
modify character_set_server by utf8mb4
modify mysql The configuration file my.cnf, Add the following configuration :
character_set_server = utf8mb4
Need to restart the database instance .
Character set before modification
mysql> show variables like "%char%";
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/soft/mysql-5.6.31/share/charsets/ |
+--------------------------+----------------------------------------+
8 rows in set
mysql> SHOW VARIABLES LIKE 'collation%';
+----------------------+--------------------+
| Variable_name | Value |
+----------------------+--------------------+
| collation_connection | utf8mb4_general_ci |
| collation_database | latin1_swedish_ci |
| collation_server | utf8_general_ci |
+----------------------+--------------------+
3 rows in set
Modified character set
mysql> show variables like "%char%";
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/soft/mysql-5.6.31/share/charsets/ |
+--------------------------+----------------------------------------+
8 rows in set
mysql> SHOW VARIABLES LIKE 'collation%';
+----------------------+--------------------+
| Variable_name | Value |
+----------------------+--------------------+
| collation_connection | utf8mb4_general_ci |
| collation_database | latin1_swedish_ci |
| collation_server | utf8mb4_general_ci |
+----------------------+--------------------+
3 rows in set
Manually set the code of the database connection to utf8mb4
JDBC Set the code of the connection :
Connection conn = DriverManager.getConnection(url, userName, password);
conn.prepareStatement("set names utf8mb4").executeQuery();
If it is Spring project , It can be downloaded from ThreadLocal Get the connection :
ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
Connection connection = connectionHolder.getConnection();
try {
PreparedStatement preparedStatement = connection.prepareStatement("SET NAMES utf8mb4");
preparedStatement.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
among dataSource Can pass Spring Inject in :
private DataSource dataSource;
Pay attention to using this method , The transaction needs to be opened , Otherwise, from ThreadLocal Can't get the connection .
Finally, pay to modify the database 、 surface 、 Character character set SQL:
-- Modify the character set of the database
alter database DBNAME DEFAULT CHARACTER SET utf8mb4;
-- Modify the character set of the table , After changing the table character set, it is only valid for the new fields
alter table tbl_name convert to character set character_name ;
-- Modify the character set of the field
alter table tbl_name change col1 col1 varchar(20) CHARACTER SET utf8mb4;
Encode the string and store , Take out decoding
Encode the string when saving into the database :
String encode = URLEncoder.encode(" Just 🧑", StandardCharsets.UTF_8.name());
Decode the string when fetching from the database :
URLDecoder.decode(encode, StandardCharsets.UTF_8.name());
边栏推荐
- Perlin noise and random terrain
- STM32 concept and installation [day 1]
- Notes - record the solution to the failure of @refreshscope dynamic refresh configuration
- Deliver temperature with science and technology, vivo protects the beauty of biodiversity
- The difference between.Split (",", -1) and.Split (",")
- Is Huatai Securities safe to open an account? How to handle it
- Jmeter+influxdb+grafana pressure measurement real-time monitoring platform construction
- [hiflow] regularly send Tencent cloud SMS sending group
- Study and use of burpsuite plug-in
- Matplotlib save image to file
猜你喜欢

Excel simple macro
深入理解微信小程序的底层框架(二)组件系统、Exparser

How to solve the problem that the universal vision NVR device is connected to the easycvr platform and cannot be online after offline?

How to solve the problem that the device video cannot be played due to the missing CGO playback callback parameters of easycvr platform?

Is software testing still popular in 2022?

通过Arduino IDE向闪存文件系统上传文件

Phpcms realizes product multi condition screening function

How CAD draws arrows with arcs

浅谈元宇宙中DeFi的可能性和局限性

Non boost ASIO notes: UDP UART socketcan multicast UDS
随机推荐
20220723 record an unexplained shutdown of SAP Oracle monitoring service
ASP.NET CORE写一个缓存Attribute工具
How to use the directory classification function of the new version of easycvr (v2.5.0)?
Vue3 uses keep alive to cache pages, but every time you switch the tab to enter the page, it will still enter onmounted, resulting in no caching effect. Why?
Basic network solutions for small and medium-sized hospitals
Phantom core is about to close? Is there a future for digital collections?
文心大模型扬起新“帆”,产业应用大潮已至
View binding confusion. I have been studying confusion for two days.
1000 okaleido tiger launched binance NFT, triggering a rush to buy
J. Serval and essay (tarjan finds topological order)
杂志特稿:元宇宙将重塑我们的生活,我们要确保它变得更好
The communication principle between native components, applets and clients, and the operation principle of video, map, canvas, picker, etc
php7 垃圾回收机制详解
Topological sorting & critical path
医院综合布线
Summary of volatile interview in concurrent programming
Talk about the top 10 mistakes often made in implementing data governance
[untitled]
Digicert code signing certificate
Ora-12899 error caused by nchar character