MySQL 8.0.13+ 支持 JSON 默认值为合法字符串或 JSON_OBJECT() 函数,5.7 不支持非 NULL 默认值;PostgreSQL jsonb 需显式类型转换;SQLite 仅 TEXT + CHECK(json_valid()) 模拟;ORM 应用字典而非字符串设默认值。
MySQL 8.0+ 直接支持 JSON 类型,但默认值不能写成字符串
mysql 5.7 起引入 json 类型,但直到 8.0.13 才允许为 json 字段设置非 null 默认值。你如果执行 alter table t add column data json default '{"a":1}',会报错:invalid default value for 'data' —— 因为 mysql 要求默认值必须是**解析后的 json 值**,不是字符串字面量。
正确做法是用 DEFAULT (JSON_OBJECT('a', 1)) 或 DEFAULT ('{"a": 1}')(仅限 8.0.13+,且引号内必须是合法 JSON):
ALTER TABLE users ADD COLUMN settings JSON DEFAULT (JSON_OBJECT('theme', 'light', 'notify', true));
- 用
JSON_OBJECT()/JSON_ARRAY()函数生成默认值最稳妥,兼容性好,语义清晰 - 直接写字符串默认值(如
DEFAULT '{"k":"v"}')只在 MySQL 8.0.13+ 支持,且字符串必须严格合法,多一个空格或单引号都会失败 -
NULL仍是所有版本都支持的默认值,但如果你业务上需要“空对象”语义,NULL和{}行为完全不同,别混用
PostgreSQL 的 jsonb 字段默认值要走 to_jsonb() 或字面量
PostgreSQL 推荐用 jsonb(二进制格式,支持索引和高效查询),但直接写 DEFAULT '{"a": 1}' 会报错:column "data" is of type jsonb but default expression is of type text —— 类型不匹配。
必须显式转换:
使用固定的 Next.js/Tailwind/Prisma 技术栈构建并记录独立 SaaS 项目,仅将 FastAPI 用于 Python 工作负载,并遵循严格的架构规范。
ALTER TABLE products ADD COLUMN metadata JSONB DEFAULT to_jsonb(('{"brand":"xyz","in_stock":true}'::json));
- 更简洁写法:
DEFAULT '{"brand":"xyz","in_stock":true}'::jsonb,强制类型标注即可 - 避免用
json类型(文本存储),它不支持 GIN 索引、键存在查询(?')、路径操作(@>)等关键能力 - 默认值里别写动态内容(比如
NOW()),jsonb默认值只接受常量表达式
SQLite 没有原生 JSON 类型,靠 TEXT + 应用层校验
SQLite 3.38.0+ 提供了 json1 扩展函数(如 json_valid()、json_extract()),但它**没有 JSON 数据类型**。字段只能定义为 TEXT,靠应用写入时保证格式,或加 CHECK 约束:
CREATE TABLE logs ( id INTEGER PRIMARY KEY, payload TEXT CHECK (json_valid(payload)) );
-
json_valid()在插入/更新时校验,非法 JSON 会触发约束失败 —— 这是 SQLite 下最接近“类型保障”的做法 - 别依赖
json_valid()做复杂逻辑(比如嵌套深度检查),它只做基础语法验证 - 默认值只能是字符串字面量:
DEFAULT '{"status":"pending"}',数据库不会自动解析或验证它是否合法(除非加 CHECK)
ORM(如 Django、SQLAlchemy)写 JSON 字段时,默认值容易漏掉序列化逻辑
Django 的 JSONField 在 PostgreSQL 上默认存 jsonb,但如果你写 default={'a': 1},Django 会自动序列化;而写 default='{"a": 1}' 就可能出问题 —— 字符串会被当作文本二次转义。
- 始终用 Python 字典/列表作为
default值(如default=dict或default={'x': 0}),让 ORM 控制序列化时机 - SQLAlchemy 的
JSON类型同理:用default={},别用default='{}' - 迁移生成的 SQL 可能不带函数包装(比如直接写
DEFAULT '{}'),在 MySQL 低版本会失败,得手动改迁移文件
JSON 字段看着简单,但默认值那块儿每个数据库的“合法写法”差得挺远,尤其是跨版本升级或换数据库时,最容易栽在那一行 DEFAULT 上。










