使用 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 原始字节,再解码为正确的中文。

原理说明

  • pymssql 在 utf8 连接模式下,将数据库返回的字节流按 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 编码的中文数据提取场景。

相关推荐
hacker_LeeFei1 小时前
Windows 下配置 Redis 8.10.2 开机自启:一次踩坑全记录
数据库·windows·redis
这个DBA有点耶2 小时前
MySQL字符集与排序规则深入:索引失效的隐蔽场景与排查方法
数据库·mysql·代码规范
zl_dfq2 小时前
Redis 之 【持久化 与 事务】
数据库·redis
闲云自留地3 小时前
从下载到登录:MySQL 在两大系统上的完整安装教程
数据库·mysql
SelectDB技术团队3 小时前
Apache Doris 高性能 Open Lake Variant 读写技术解析(含对比数据)
数据结构·数据库·clickhouse·日志·apache doris·selectdb·湖仓架构升级
一 乐3 小时前
博客管理系统|基于springboot + vue博客管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕设
茉莉玫瑰花茶3 小时前
GO [ 类型 ]
开发语言·数据库·golang
ClouGence3 小时前
开源数据库管理工具 CloudDM 4.3.0 发布,支持 SQL 收藏,多数据源语法支持大幅增强
数据库·oracle·sql server
Summer-Bright4 小时前
深度 | 壁仞1.74亿中标智算中心:国产GPU从能用跨进商用,但4.5亿的大单却因凑不齐三家废标了
数据库·ai·国产gpu
云安全助手4 小时前
自建接入VS聚合平台:企业 AI 调用的选型思路与迁移成本拆解
java·大数据·数据库·人工智能·ai大模型