必须使用json类型列并校验兼容性:mysql需定义data json列并用isjson()验证;sql server要求兼容性级别≥130且显式用isjson()过滤;postgresql推荐jsonb类型,写入即校验。

直接用 INSERT 往非 JSON 类型字段里塞 JSON 字符串,十有八九会失败——不是语法报错,就是后续查出来是 NULL 或乱码。根本原因不是 SQL 写错了,而是没处理好三层矛盾:字符串转义、列类型校验、数据库版本兼容性。
MySQL 插入前必须确认列类型是 JSON
如果字段是 VARCHAR 或 TEXT,数据库不会校验 JSON 合法性,插入成功但后续 JSON_EXTRACT() 会返回 NULL,甚至 JSON_VALID() 都可能误判(比如尾随逗号、单引号)。只有声明为 JSON 类型,才能在 INSERT 时强制拦截非法数据。
- 建表时直接定义:
CREATE TABLE logs (id INT, data JSON) - 已有表需修改:
ALTER TABLE logs MODIFY COLUMN data JSON(注意:该操作会锁表,生产环境慎用) - 验证是否生效:
SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'logs' AND COLUMN_NAME = 'data',结果应为json
SQL Server 必须检查兼容性级别 ≥130
ISJSON()、JSON_VALUE() 这些函数在 SQL Server 2016+ 才支持,但前提是数据库兼容性级别不低于 130。否则函数不可用,INSERT 也不会校验格式,等于裸奔。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 查当前级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME() - 升级命令:
ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 150(推荐 150,避免新函数不可用) - 即使列是
NVARCHAR(MAX),也必须显式用WHERE ISJSON(payload) = 1过滤,不能跳过
PostgreSQL 推荐用 jsonb 而非 json
json 类型只做字符串存储,不解析、不校验、不索引;jsonb 在写入时就解析并二进制化,自动去重键、标准化空格、拒绝无效 JSON,查询还支持 GIN 索引。
- 建表用:
CREATE TABLE events (id SERIAL, payload JSONB) - 插入时无需额外校验:
INSERT INTO events (payload) VALUES ('{"a": 1, "b": [2,3]}'),非法 JSON 直接报错 - 若已有
json列,可转换:ALTER TABLE events ALTER COLUMN payload TYPE JSONB USING payload::JSONB
所有数据库都绕不开的转义陷阱
用户输入、日志文本、富文本内容里常含换行符、双引号、反斜杠——这些字符在拼进 JSON 字符串前没处理,JSON_OBJECT() 就会崩。关键不是“能不能转义”,而是“谁来转、什么时候转”。
- 绝对不要在应用层拼 SQL 字符串:
"INSERT ... VALUES ('" + json.dumps(...) + "')是高危操作 - MySQL 清洗顺序必须是:
REPLACE(REPLACE(REPLACE(col, '\', '\\'), '"', '\"'), ' ', '\n'),反斜杠必须最先处理 - PostgreSQL/SQL Server 应优先用参数化查询或内置函数:
jsonb_build_object('msg', %s)或JSON_MODIFY(),让驱动或数据库处理转义
最易被忽略的一点:批量导入时,临时表字段类型、字符集、客户端连接的 sql_mode(MySQL)或 ANSI_NULLS(SQL Server)都会影响 JSON 解析行为——别只盯着 INSERT 语句本身。










