`

MySQL-JDBC 编码问题

 
阅读更多

测试配置

用户实例配置,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(); -->

   encoding.jpg

    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

  1. 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

 

    传递参数.jpg

 

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的编码语言和服务端是一致的。

  encoding.jpg

 

 

 

 

 

分享到:
评论

相关推荐

    mysql-jdbc驱动包8.0.11

    MySQL JDBC驱动包8.0.11是MySQL官方发布的用于Java应用程序与MySQL数据库进行通信的驱动程序。JDBC(Java Database Connectivity)是Java平台中的一种标准API,它允许Java程序员使用SQL语句来访问和操作数据库。这个...

    mysql-connector-java Linux下MySQL的JDBC驱动Jar包

    MySQL的JDBC驱动,即“mysql-connector-java”,是一个实现了JDBC接口的Java库,使得Java程序能够在运行时连接到MySQL服务器。该驱动程序由MySQL官方提供,支持各种版本的MySQL数据库。 3. “mysql-connector-java...

    elasticsearch-jdbc-2.3.3.0-dist.zip

    3. **数据映射与转换**: 数据从MySQL导入Elasticsearch时,可能会涉及类型转换,如日期格式、字符串编码等。用户需要确保MySQL中的数据类型与Elasticsearch的映射正确,以保证数据的一致性和可用性。 4. **全文搜索...

    Spring-JDBC整合-MySQL8、java8版本

    Spring JDBC 提供了 JdbcTemplate 和 NamedParameterJdbcTemplate,这两个工具类极大地减少了我们处理数据库连接、事务管理、结果集映射等工作所需的手动编码。 首先,集成Spring JDBC需要引入相应的jar包。在现代...

    mysql-jdbc驱动

    9. **字符集支持**:MySQL JDBC驱动可以配置字符集,确保数据在Java应用和MySQL数据库之间的正确编码和解码。 10. **断线重连与心跳检测**:在长时间无操作或者网络不稳定的情况下,驱动能检测到连接失效并尝试自动...

    mysql-connector-java-5.1.35 MySQL的jdbc驱动jar

    总结来说,MySQL Connector/J 5.1.35是连接Java应用与MySQL数据库的关键工具,它提供了丰富的功能,包括数据访问、事务处理、性能优化等,同时也需要开发者关注安全性和版本兼容性问题。在实际开发中,正确配置和...

    mysql-jdbc5.1.7.rar

    7. **JDBC驱动配置**:MySQL JDBC驱动可以通过JDBC URL进行配置,例如设置字符编码、连接超时、使用SSL等。例如,`jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8`。 8. **性能优化**:...

    该项目主要采用springboot2.x+sharding -spring-boot-sharding-jdbc.zip

    而Sharding-JDBC作为一款轻量级的数据库分片中间件,无需额外部署,只需在Java代码中引入依赖即可实现数据库的水平扩展,有效解决了单表数据量过大导致的性能问题。本文将深入探讨如何在SpringBoot2.x项目中结合...

    mysql-connector-java-5.1.27

    这个驱动包允许Java程序通过JDBC(Java Database Connectivity)接口连接到MySQL服务器,执行SQL查询、事务处理等数据库操作。 `mysql-connector-java-5.1.27.jar`是该驱动包的核心文件,包含了所有必要的类和资源...

    mysqll连接所需jar包mysql-connector-java-5.1.23-bin

    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-connector-java-8.0.28 是MySQL数据库与Java应用程序之间通信的重要组件,它是一个JDBC(Java Database Connectivity)驱动程序,使得Java开发者能够通过编写Java代码来访问和操作MySQL数据库。在这个版本中,...

    mysql-connector-java-5.1.15-bin.jar.zip

    1. **MySQL驱动程序**:MySQL驱动程序是Java应用程序与MySQL服务器之间的桥梁,实现了JDBC(Java Database Connectivity)接口。JDBC是Java标准,允许Java程序通过API来访问各种类型的数据库。`mysql-connector-java...

    Mysql数据库驱动mysql-connector-java-5.1.41-bin.jar

    - 编码处理:自动处理字符编码问题,确保数据正确传输。 - 事务处理:支持ACID(原子性、一致性、隔离性、持久性)事务特性。 - 其他特性:包括预编译的SQL语句(PreparedStatement)、批处理、存储过程调用等。 ...

    linux mysql-connector-java-5.1.36.tar.gz

    MySQL Connector/J遵循JDBC(Java Database Connectivity)标准,使得Java开发者可以利用Java语言来编写能够与MySQL数据库交互的应用程序。JDBC是Java API,它的主要任务是为Java程序员提供一个统一的接口,以访问...

    MySQL驱动jar包(mysql-connector-java)

    `mysql-connector-java`是MySQL官方提供的JDBC驱动,符合JDBC规范,使得Java程序可以无缝连接到MySQL数据库。 2. **版本兼容性**:`mysql-connector-java-5.4.40.jar`是特定版本的驱动,5.4系列适用于MySQL 5.x到8....

    mysql-connector-java-5.1.46.jar

    MySQL Connector/J是MySQL数据库与Java应用程序之间的桥梁,它是一个实现了JDBC(Java Database Connectivity)标准的驱动程序,使得Java开发者能够方便地在Java应用中访问MySQL数据库。"mysql-connector-java-...

    mysql-connector-java-5.1.30-bin.rar

    MySQL是世界上最受欢迎的关系型数据库管理系统之一,而MySQL Connector/J则是MySQL官方提供的用于Java应用程序的数据访问接口,它实现了Java Database Connectivity (JDBC) API。在本案例中,我们关注的是"mysql-...

    Eclipse连接MySQL驱动——mysql-connector-java-bin(解压即用)

    在Eclipse中连接MySQL数据库,需要一个关键的组件——MySQL的Java连接器(JDBC驱动),即mysql-connector-java。本篇将详细介绍如何在Eclipse中使用`mysql-connector-java-bin.jar`来实现与MySQL数据库的连接。 ...

Global site tag (gtag.js) - Google Analytics