使用 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 编码的中文数据提取场景。

相关推荐
snow@li7 小时前
数据库:市场中都有哪些数据库 / 优缺点 使用情况
数据库
NoSi EFUL8 小时前
MySQL中ON DUPLICATE KEY UPDATE的介绍与使用、批量更新、存在即更新不存在则插入
android·数据库·mysql
河阿里8 小时前
SQL数据库:五大范式(NF)
数据库·sql·oracle
l1t9 小时前
DeepSeek总结的PostgreSQL 19查询提示功能
数据库·postgresql
chenxu98b10 小时前
MySQL如何执行.sql 文件:详细教学指南
数据库·mysql
刘晨鑫111 小时前
MongoDB数据库应用
数据库·mongodb
梦想的颜色11 小时前
mongoTemplate + Java 增删改查基础介绍
数据结构·数据库·mysql
小小小米粒12 小时前
redis命令集合
数据库·redis·缓存
herinspace12 小时前
管家婆实用贴-如何分离和附加数据库
开发语言·前端·javascript·数据库·语音识别
步辞13 小时前
Go语言怎么用channel做信号通知_Go语言channel信号模式教程【完整】
jvm·数据库·python