测试配置
用户实例配置,my.cnf [mysqld] default-character-set = gbk
测试结论
characterEncodingAsString 为JDBC中的字符编码
serverCharsetIndex 为jdbc中存储的server端编码
serverCharSet (我们用这个变量来代表实际mysql server会话连接编码)
当调用setNames的时候jdbc的上面两个值都没有更新,但是mysql server端是更新了,所以出现了乱码。
without characterEncoding=UTF-8 | with characterEncoding=UTF-8 | |
doHandshake阶段 |
characterEncodingAsString = null serverCharsetIndex = 28 (GBK) serverCharSet = gbk
socket交互统一使用characterEncodingAsString 如果为null,则使用UTF-8
|
characterEncodingAsString = utf8 serverCharsetIndex = 28 (GBK) serverCharSet = utf8
jdbc同socket交互统一使用characterEncodingAsString 也就是UTF-8,其实这里我猜测发送了个set name utf8命令过去了,具体代码得看下mysql的源码了。
|
configureClientCharacterSet阶段 |
characterEncodingAsString = GBK serverCharsetIndex = GBK serverCharSet = gbk
|
characterEncodingAsString = utf8 serverCharsetIndex = 28 (GBK) serverCharSet = utf8
|
执行SQL阶段 | 此时执行SQL都是使用GBK编码所以不会乱码 |
其实本以为这里会乱码的,后来想明白了,原来serverCharsetIndex = 28这个值在jdbc里面已经是错误的了,不用关注。虽然JDBC内部两个变量不一致,但 是characterEncodingAsString 和mysql server端的编码方式是一致的。 |
set names utf8 |
characterEncodingAsString = GBK serverCharsetIndex = gbk serverCharSet = utf8 此时的jdbc端是错误的 但是此时的server的连接已经切换成utf8
|
同样不会乱码 |
set names gbk |
jdbc characterEncodingAsString = utf8 serverCharsetIndex = 28 (GBK) serverCharSet = gbk
|
|
执行SQL阶段 |
此时JDBC将SQL转为GBK,而同时服务端使用的是UTF8编码 所以出现乱码问题 |
执行失败,中文乱码了。 因为characterEncodingAsString 和serverCharSet 不一致。 |
JDBC URL不带characterEncoding=UTF-8的测试场景
1. doHandshake前阶段
从ConnectionImpl.java定位到ConnectionImpl()函数里面的
initializeDriverProperties(info); -->
postInitialization(); -->
this.characterEncodingAsString = ((String) this.characterEncoding.getValueAsObject());
从这里可以看出characterEncodingAsString这个变量取值是null
2. doHandshake阶段
从ConnectionImpl.java定位到ConnectionImpl()函数里面的 -->
createNewIO(false);-->
connectOneTryOnly(isForReconnect, mergedProps); -->
coreConnect(mergedProps); -->
this.io.doHandshake(this.user, this.password, this.database);-->
this.serverCharsetIndex = buf.readByte() & 0xff;
这里可以看出mysql server socket 用一个int表示编码类型,
具体mysql server从根据哪个参数的编码类型来发这个int 需要查看mysql源码,猜测是default-character-set
其实里面有个map根据这个int 就可以获取到相应的编码类型
this.io.doHandshake(this.user, this.password, this.database);-->
secureAuth411(null, packLength, user, password, database, true); -->
String enc = getEncodingForHandshake(); -->
packet.writeString(user, enc, this.connection); -->
writeStringNoNull(s, encoding, encoding, false, conn);
3.configureClientCharacterSet阶段
connectOneTryOnly(isForReconnect, mergedProps); -->
initializePropsFromServer(); -->
configureClientCharacterSet(false); -->
获取第二步编码类型
realJavaEncoding = getEncoding(); // 获取url的编码 这里是null
String serverEncodingToSet = CharsetMapping.getJavaEncodingForCollationIndex(this.io.serverCharsetIndex);
setEncoding(serverEncodingToSet);
这里差不多完成了编码的赋值,执行executeSQL的时候就会调用这两种编码。
JDBC URL带characterEncoding=UTF-8
-
doHandshake前阶段
代码同上可以看到characterEncodingAsString 已经能够取到utf8,所以使用socket验证的时候都会使用utf8编码进行。
this.characterEncodingAsString = ((String) this.characterEncoding.getValueAsObject());
这个props参数中包含了characterEncoding=UTF-8属性,所以猜测mysql server接受到的报文中含有这个参数,会自动
调用set names utf8。因为JDBC源码中发现没有在这里设置set names但是连接的character_set_client,character_set_connection
的两个变量都从gbk变成了utf8。
character_set_client
2. doHandshake阶段
和上面类似。
3.configureClientCharacterSet阶段
realJavaEncoding = getEncoding(); // 获取url的编码 这里是null
String serverEncodingToSet = CharsetMapping.getJavaEncodingForCollationIndex(this.io.serverCharsetIndex);
setEncoding(serverEncodingToSet);
代码已经将characterEncodingAsString 设置成GBK因为mysql server是GBK的
这块比较特殊,发现代码的后面还会将characterEncodingAsString设置成UTF-8,
所以在jdbc中debug的时候这两个编码不一样,却不出现乱码,因为jdbc的编码语言和服务端是一致的。
相关推荐
MySQL的JDBC驱动,即“mysql-connector-java”,是一个实现了JDBC接口的Java库,使得Java程序能够在运行时连接到MySQL服务器。该驱动程序由MySQL官方提供,支持各种版本的MySQL数据库。 3. “mysql-connector-java...
3. **数据映射与转换**: 数据从MySQL导入Elasticsearch时,可能会涉及类型转换,如日期格式、字符串编码等。用户需要确保MySQL中的数据类型与Elasticsearch的映射正确,以保证数据的一致性和可用性。 4. **全文搜索...
MySQL JDBC驱动包8.0.11是MySQL官方发布的用于Java应用程序与MySQL数据库进行通信的驱动程序。JDBC(Java Database Connectivity)是Java平台中的一种标准API,它允许Java程序员使用SQL语句来访问和操作数据库。这个...
Spring JDBC 提供了 JdbcTemplate 和 NamedParameterJdbcTemplate,这两个工具类极大地减少了我们处理数据库连接、事务管理、结果集映射等工作所需的手动编码。 首先,集成Spring JDBC需要引入相应的jar包。在现代...
9. **字符集支持**:MySQL JDBC驱动可以配置字符集,确保数据在Java应用和MySQL数据库之间的正确编码和解码。 10. **断线重连与心跳检测**:在长时间无操作或者网络不稳定的情况下,驱动能检测到连接失效并尝试自动...
总结来说,MySQL Connector/J 5.1.35是连接Java应用与MySQL数据库的关键工具,它提供了丰富的功能,包括数据访问、事务处理、性能优化等,同时也需要开发者关注安全性和版本兼容性问题。在实际开发中,正确配置和...
7. **JDBC驱动配置**:MySQL JDBC驱动可以通过JDBC URL进行配置,例如设置字符编码、连接超时、使用SSL等。例如,`jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8`。 8. **性能优化**:...
而Sharding-JDBC作为一款轻量级的数据库分片中间件,无需额外部署,只需在Java代码中引入依赖即可实现数据库的水平扩展,有效解决了单表数据量过大导致的性能问题。本文将深入探讨如何在SpringBoot2.x项目中结合...
这个驱动包允许Java程序通过JDBC(Java Database Connectivity)接口连接到MySQL服务器,执行SQL查询、事务处理等数据库操作。 `mysql-connector-java-5.1.27.jar`是该驱动包的核心文件,包含了所有必要的类和资源...
MySQL Connector/J是MySQL的Java数据库驱动程序,符合JDBC(Java Database Connectivity)标准。版本5.1.23是在2012年发布的一个稳定版本,它支持多种Java平台,并且兼容MySQL 5.1.x系列服务器。这个驱动包提供了与...
MySQL-connector-java-8.0.28 是MySQL数据库与Java应用程序之间通信的重要组件,它是一个JDBC(Java Database Connectivity)驱动程序,使得Java开发者能够通过编写Java代码来访问和操作MySQL数据库。在这个版本中,...
1. **MySQL驱动程序**:MySQL驱动程序是Java应用程序与MySQL服务器之间的桥梁,实现了JDBC(Java Database Connectivity)接口。JDBC是Java标准,允许Java程序通过API来访问各种类型的数据库。`mysql-connector-java...
- 编码处理:自动处理字符编码问题,确保数据正确传输。 - 事务处理:支持ACID(原子性、一致性、隔离性、持久性)事务特性。 - 其他特性:包括预编译的SQL语句(PreparedStatement)、批处理、存储过程调用等。 ...
`mysql-connector-java`是MySQL官方提供的JDBC驱动,符合JDBC规范,使得Java程序可以无缝连接到MySQL数据库。 2. **版本兼容性**:`mysql-connector-java-5.4.40.jar`是特定版本的驱动,5.4系列适用于MySQL 5.x到8....
MySQL Connector/J是MySQL数据库与Java应用程序之间的桥梁,它是一个实现了JDBC(Java Database Connectivity)标准的驱动程序,使得Java开发者能够方便地在Java应用中访问MySQL数据库。"mysql-connector-java-...
MySQL是世界上最受欢迎的关系型数据库管理系统之一,而MySQL Connector/J则是MySQL官方提供的用于Java应用程序的数据访问接口,它实现了Java Database Connectivity (JDBC) API。在本案例中,我们关注的是"mysql-...
在Eclipse中连接MySQL数据库,需要一个关键的组件——MySQL的Java连接器(JDBC驱动),即mysql-connector-java。本篇将详细介绍如何在Eclipse中使用`mysql-connector-java-bin.jar`来实现与MySQL数据库的连接。 ...
10. **字符编码处理**: MySQL Connector/J处理了各种字符编码问题,确保Java字符串和数据库中的数据正确交互。在源码中,我们可以看到`com.mysql.jdbc.CharsetMapper`和`com.mysql.jdbc.StringUtils`的相关实现。 ...