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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值