mysql数据校验过程中的字符集问题处理

 更新时间:2014年05月13日 16:10:15   作者:  
在日常应用中,我们经常会遇到在不同的字符集的数据库直接进行数据的导入导出操作,针对这个问题,我们来进行讨论下

场景:
主库DB:utf8字符集
备库DB:gbk字符集

需求:
校验主备数据是否一致,并且修复

校验过程:
设置主库连接为utf8,设置备库连接为gbk,分别进行查询,将返回的的结果集按记录逐字段比较。

显示结果:
原本相同的汉字字符,数据校验认为不一致。

原因分析:
对于主库而已,由于建立连接的字符集为UTF8,则返回的汉字字符编码为UTF8格式;对于备库而言则是GBK格式,而程序中通过字符串比较函数strcasecmp进行比较,显然不同的字符集编码,相同的字符有不同的二进制,因此结果肯定不会相等。

进一步分析:
那么对于这种情况,建立连接应该采用哪种字符集呢?GBK or UTF8。其实选择任何一种字符集都是OK的,只要是访问主库和备库的字符集保持一致即可,唯一的区别在于,若选择的字符集与客户端的字符集不一致,可能导致无法正常显示字符,即字符显示为乱码。

我们以客户端的字符集为例,详细说说三种情况:【这里的客户端可以认为是SecureCRT】
备注:绿色框代表DB字符集,黄色框代表连接字符集,橙色框代表客户端
第一种情况:

就是上述的情况,主库返回字符的GBK编码,备库返回字符的UTF8编码,因此进行字段比对,则会出现误差。

第二种情况:

访问主库的连接不变,备库连接由UTF8变为GBK,因此进行返回时,数据库会将DB的字符集转为GBK返回给客户端,那么对于客户端而已,相同字符都是通过GBK编码表示,因此二进制相等,校验结果正确。

第三种情况:

   访问主库和备库的连接都是UTF8,因此对于主库而已,返回给客户端的字符编码由GBK转为UTF8,此时主库和备库都是UTF8编码,校验结果正确。但由于客户端实质是GBK编码方式显示,因此返回的汉字字符都是乱码,但不影响校验结果的正确性。

修复:

      既然选择与主备库任一一个相同的字符集去访问,都不会影响校验结果的正确性,那么影响修复呢?由于UTF8的编码范围比GBK编码范围要大,因此若采用GBK连接访问UTF8编码DB,有可能出现部分字符GBK不能表示的情况。

我们拿第二种情况说明,此时主库为GBK,备库为UTF8,使用GBK访问UTF8。假设存在UTF8转为GBK过程中部分字符丢失,这时候主备库肯定是不一致的,因为存在部分字符GBK无法表示。 假设修复语句如下:

Update  t set c1=master_value  where  c1=slave_value  and id=?

其中t表示表名,id是主键表示某一行,master_value为主库c1列的值,slave_value为备库c1列的值。此时,slave_value由于UTF8转为GBK已经丢失,因此语句执行最终影响0行记录,无法修复。

 

结论:

客户端访问两个不同字符集库进行数据校验时,连接采用表示范围更大的字符集。比如我们常用的字符集表示范围如下:

Latin<gb2312<gbk<utf8

 

附:mysql客户端与服务器通信时字符集编码转换流程

相关参数:

– character_set_client:客户端来源数据使用的字符集

– character_set_connection:连接层字符集

– character_set_results:查询结果字符集

– character_set_database:当前选中数据库的默认字符集

– character_set_system:系统元数据(字段名等)字符集

 1.客户端请求服务器

1)将client的字符集转为connection字符集

2)将connection字符集转为DB内部的字符集

 

 2.服务器返回结果给客户端

1)将DB内部字符集转为connection字符集

2)将connection字符集转为character_set_results字符集

 

3.设置字符集命令:set names 字符编码

指定客户端与服务器通信的字符集,包括请求与返回。

SET NAMES 'x'  等价于:

SET character_set_client = x;

SET character_set_results = x;

SET character_set_connection = x;

附图:

相关文章

  • MySQL四种日志binlog/redolog/relaylog/undolog详解

    MySQL四种日志binlog/redolog/relaylog/undolog详解

    undo log主要存储的也是逻辑日志,比如我们要insert一条数据了,那undo log会记录的一条对应的delete日志,我们要update一条记录时,它会记录一条对应相反的update记录,这篇文章主要介绍了MySQL四种日志binlog/redolog/relaylog/undolog,需要的朋友可以参考下
    2024-08-08
  • mysql派生表(Derived Table)简单用法实例解析

    mysql派生表(Derived Table)简单用法实例解析

    这篇文章主要介绍了mysql派生表(Derived Table)简单用法,结合实例形式分析了mysql派生表的原理、简单使用方法及操作注意事项,需要的朋友可以参考下
    2019-12-12
  • mysqlsla慢查询分析工具使用笔记

    mysqlsla慢查询分析工具使用笔记

    mysqlsla是一款帮助语句分析、过滤、和排序的功能,能够处理MySQL慢查询日志、二进制日志等。整体来说, 功能非常强大. 能制作SQL查询数据报表,分析包括执行频率, 数据量, 查询消耗等
    2014-05-05
  • MySQL深分页问题解决思路

    MySQL深分页问题解决思路

    这篇文章主要介绍了优雅地解决mysql深分页问题,本文将会讨论当mysql表大数据量的情况,如何优化深分页问题,并附上最近的优化慢sql问题的案例伪代码,需要的朋友可以参考下
    2022-12-12
  • MySQL视图简介及基本操作教程

    MySQL视图简介及基本操作教程

    这篇文章主要给大家介绍了关于MySQL视图简介及基本操作的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • mysql 启动1067错误及修改字符集重启之后复原无效问题

    mysql 启动1067错误及修改字符集重启之后复原无效问题

    这篇文章主要介绍了mysql 启动1067错误及修改字符集重启之后复原无效问题,需要的朋友可以参考下
    2017-10-10
  • MySQL入门(二) 数据库数据类型详解

    MySQL入门(二) 数据库数据类型详解

    这个数据库所遇到的数据类型今天统统在这里讲清楚了,以后在看到什么数据类型,咱度应该认识,对我来说,最不熟悉的应该就是时间类型这块了。但是通过今天的学习,已经解惑了。下面就跟着我的节奏去把这个拿下吧
    2018-07-07
  • MySQL使用聚合函数进行单表查询

    MySQL使用聚合函数进行单表查询

    这篇文章主要介绍了MySQL使用聚合函数进行单表查询,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • MySQL8数据库安装及SQL语句详解

    MySQL8数据库安装及SQL语句详解

    本文详细讲解了MySQL8数据库安装及SQL语句用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • Mysql中有关Datetime和Timestamp的使用总结

    Mysql中有关Datetime和Timestamp的使用总结

    mysql数据库常用的时间类型有timestamp和datetime,两者主要区别是占用存储空间长度不一致、可存储的时间也有限制,本文就来详细的介绍一下,感兴趣的可以了解一下
    2021-12-12

最新评论