使用 pymssql 连接数据库(GBK 编码)乱码问题的完美解决方案

背景

在对接国内一些早期开发的 ERP、物流、一卡通等系统时,SQL Server 数据库中的中文数据常常采用 GBK 编码 存储。

然而 pymssql 在连接时若使用 charset='utf8',读取出来的中文字符会呈现为"乱码"------实际上是 UTF-8 解码 GBK 字节导致的现象。

直接修改连接字符集为 charset='gbk' 又可能引发其他字段(如数字、英文、特殊符号)的异常,甚至导致连接失败。

本文将结合真实案例,提供一个 稳定、可复现 的乱码修复方案。

问题现象

某物流系统数据库,表结构如下:

复制代码
CREATE TABLE t_record (
    s_vehicle_no VARCHAR(50),   -- 车牌号(中文)
    s_remark VARCHAR(200),      -- 备注(中文)
    ...
);

使用 pymssql 查询结果:

复制代码
{
    '车牌号': '沪A12345',   # 实际应为"沪A12345"
    '备注': '包装损坏'    # 实际应为"包装损坏"
}

这类乱码特征明显:英文字符正常,中文字符变为多字节乱码

错误尝试

1. 直接修改连接字符集

复制代码
DB_CONFIG = {
    'charset': 'gbk'
}

结果:

  • 某些字符集下查询报错(如 UnicodeDecodeError

  • 数字、英文可能被错误转换

  • pymssql 内部处理机制不兼容

2. 手动 encode/decode

复制代码
value.encode('latin-1').decode('gbk')

有效,但需要明确区分哪些字段是中文、哪些不是,无法通用。

最终解决方案

核心思路

统一使用 charset='utf8' 连接 ,在读取后将所有字符串字段通过 "拉丁-1 中转" 方式还原为 GBK 原始字节,再解码为正确的中文。

原理说明

  • pymssqlutf8 连接模式下,将数据库返回的字节流按 UTF-8 解码

  • 若数据库实际存储为 GBK,则会被错误解码成"假 Unicode 字符串"。

  • 修复过程:

    1. 将该字符串按 latin-1(单字节无损编码)转回原始字节

    2. GBK 重新解码

    3. 得到真实中文

    import pymssql

    def fix_gbk_text(text):
    """修复 pymssql + utf8 模式下的 GBK 乱码"""
    if text is None or not isinstance(text, str):
    return text
    try:
    return text.encode('latin-1').decode('GBK')
    except:
    return text

    def get_clean_data(order_no):
    conn = pymssql.connect(
    server='192.168..',
    user='',
    password='
    ',
    database='******',
    charset='utf8'
    )
    cursor = conn.cursor(as_dict=True)

    复制代码
      sql = """
      SELECT TOP 1
          s_vehicle_no AS 车牌号,
          s_remark AS 备注
      FROM t_record
      WHERE s_code = %s
      """
    
      cursor.execute(sql, (order_no,))
      row = cursor.fetchone()
    
      if row:
          clean_row = {}
          for key, value in row.items():
              if isinstance(value, str):
                  clean_row[key] = fix_gbk_text(value)
              else:
                  clean_row[key] = value
          return clean_row
      else:
          return None

验证结果

修复前:

复制代码
{
    '车牌号': '沪A12345',
    '备注': '包装损坏'
}

修复后:

复制代码
{
    '车牌号': '沪A12345',
    '备注': '包装损坏'
}

适用场景

该方案适用于以下情况:

  • SQL Server 数据库,中文采用 GBK / GB2312 / GB18030 编码

  • 使用 pymssql 且无法修改数据库端编码

  • 需要同时保留数字、英文、Decimal、日期等非字符串类型的原始格式


注意事项

  1. 仅修复字符串字段:数字、布尔值、Decimal 等类型无需处理,直接保留。

  2. 性能影响极小:仅在查询结果集上做一次遍历修复,适合中小规模数据。

  3. 兼容性好:修复失败的字段会返回原值,不会导致程序崩溃。

  4. 适用于多表 JOIN:无论多少字段,统一遍历修复即可。


总结

在国内企业信息化系统中,GBK 编码的中文数据库依然广泛存在。
pymssql 默认的 UTF-8 连接方式虽然保证了跨平台兼容性,但在处理老系统数据时容易出现乱码。

本文提供了一种 无侵入、易封装、可复用 的修复模式,能够在不修改数据库、不改变连接配置的前提下,干净地还原真实中文数据。

该方案已在实际生产环境中稳定运行,适用于各类 GBK 编码的中文数据提取场景。

相关推荐
却话巴山夜雨时i2 小时前
互联网大厂Java面试场景:从Spring到微服务的逐层提问
java·数据库·spring·微服务·日志·性能监控
oradh2 小时前
Oracle数据库网络体系结构概述
数据库·oracle·数据库基础·数据库入门·oracle网络基础
满天星83035772 小时前
【MySQL】表的基本查询(上)
linux·服务器·数据库·mysql
主角1 72 小时前
MySQL高可用集群
数据库·mysql
dajun1811234562 小时前
信息系统运维管理全流程详解 在线画图工具绘制运维流程图表技巧
运维·数据库·信息可视化·流程图·旅游·论文笔记
流觞 无依2 小时前
SQLite数据库损坏修复指南——解决“database disk image is malformed”报错
jvm·数据库·sqlite
道清茗2 小时前
【MySQL知识点问答题】 安全与性能管理
数据库·mysql
2501_920627613 小时前
Flutter 框架跨平台鸿蒙开发 - 数据库学习助手
数据库·学习·flutter·华为·harmonyos
ZStack开发者社区3 小时前
阿里云 × ZStack:云端管得好,边端交付稳
数据库·边缘计算