必须在数据触碰JSON函数前校验:MySQL用JSON_VALID()加CHECK约束,SQL Server用ISJSON()配合NVARCHAR(MAX),PostgreSQL优选JSONB类型,Python需统一转str再json.loads()。

MySQL插入前必须用JSON_VALID()预检
直接INSERT一个看似合法的字符串,比如'{"name": "Alice", "age": 25}',可能成功;但若混入控制字符(\u0000)、单引号冒充双引号({'name': 'Alice'})或BOM头,JSON_VALID()会立刻返回0,而INSERT仍会静默写入TEXT字段——后续所有JSON_EXTRACT()都拿不到值,且不报错。
实操建议:
- 建表时加CHECK约束:
ADD CONSTRAINT valid_json CHECK (JSON_VALID(data)),让非法数据在INSERT时直接被拒 - 批量导入前先过滤:
SELECT raw FROM staging WHERE JSON_VALID(raw) = 0 LIMIT 10,定位脏数据源头 - 空字符串
''和NULL都不通过JSON_VALID(),需显式排除:WHERE raw != '' AND raw IS NOT NULL
SQL Server要先用ISJSON()再插
ISJSON()返回1才代表可安全传给JSON_VALUE()或OPENJSON()。如果跳过这步,遇到"{key: 1}"(key没双引号)这种常见前端错误,执行JSON_VALUE(json_detail, '$.key')会报错JSON text is not properly formatted. Unexpected character '.' is found at position 1.(错误码13609)。
实操建议:
- 插入语句里嵌套校验:
INSERT INTO wm_json_demo (json_detail) SELECT @input WHERE ISJSON(@input) = 1 - 别用
TEXT类型存JSON——ISJSON()和JSON_VALUE()都不支持,必须用NVARCHAR(MAX)或VARCHAR(MAX) - 前端传来的JSON若含HTML实体(如
"),得先在应用层解码,SQL Server不自动处理
PostgreSQL用JSONB类型自动拦错
选JSONB而不是JSON类型,插入非法JSON会直接报错invalid input syntax for type jsonb,而不是容忍它入库。这是最省心的防线——因为JSONB在写入时就解析并标准化(去空格、去重键、转二进制),后续查询快,且天然拒绝格式错误。
实操建议:
- 建表用
json_detail JSONB,别用json_detail JSON - 想兼容原始格式?用
JSONB_PRETTY()输出时美化,但存储仍走JSONB - 从CSV或外部系统导入时,先用
jsonb_typeof(col)查类型,NULL表示解析失败,可配合CASE WHEN分流处理
Python读出后json.loads()报错的真正原因
不是JSON本身错,而是数据库驱动返回的类型混乱:PyMySQL默认把JSON字段当bytes返回,psycopg2对JSONB可能返回dict(取决于适配器配置),json.loads()只认str或bytes,传dict进去就炸。
实操建议:
- 统一转
str再loads:data_str = row['json_col'].decode('utf-8') if isinstance(row['json_col'], bytes) else str(row['json_col']) - 用
json.dumps(row['json_col'])反向序列化再loads()也行,但多一次序列化开销 - ORM如SQLAlchemy,确认
JSON列类型是否启用了自动解析(如sqlalchemy.dialects.postgresql.JSONB默认不解析,需手动ast.literal_eval)


















