优先用传统字段而非json存名片数据:文字类字段拆列并建索引,图片存相对路径,动态字段用扩展表,搜索用前缀匹配+拼音字段,通知异步解耦,富文本须过滤xss。

用 TEXT 还是 JSON 字段存名片图文混合数据?
MySQL 8.0+ 支持 JSON 类型,但个人名片系统里,别一上来就选 JSON。它查起来不走索引(除非建虚拟列+索引),更新单个字段还得全量写入,反而拖慢高频读写的名片详情页。真正适合的场景是:字段结构稳定、查询条件明确(比如按公司名查、按职位模糊搜)——这时候用传统字段更直接。
常见错误现象:JSON 存了 {"name":"张三","avatar":"/imgs/a1.jpg"},结果想按 avatar 路径做 CDN 预加载,却发现没法在 WHERE 里高效过滤;或者前端传回修改后的整个 JSON,后端没做 diff 就 UPDATE,白白触发 binlog 和从库同步。
- 头像、二维码等二进制内容,一律存路径(
VARCHAR(255)),文件本身走对象存储(OSS/S3) - 文字类字段(姓名、电话、职位、公司、简介)拆成独立列,加好
INDEX(比如INDEX idx_company (company)) - 如果真有动态扩展字段(如“微信 ID”“钉钉号”“小红书主页”),用单独的
profile_ext表 +key/value结构,别塞 JSON
图片路径怎么存才不怕迁移和 CDN 切换?
硬编码域名或协议("https://cdn.example.com/xxx.jpg")是典型坑。一旦换 CDN 域名或上 HTTPS 强制跳转,所有老数据就裂开;本地开发环境还可能直接 404。
正确做法是只存相对路径或资源标识符,由应用层拼接前缀。数据库里字段定义为 avatar_path VARCHAR(255),值为 "u/123/avatar_v2.jpg" 这类无协议、无域名的路径。
- 避免存完整 URL,包括
http://或//开头的协议相对 URL - 路径中别含用户 ID 明文(如
"uid_789/avatar.jpg"),防止被枚举;可用短哈希或服务端映射 - 如果支持多图(如名片背面扫描件),用关联表
card_images,而不是在主表加多个img1/img2字段
如何让搜索姓名/公司时支持中文分词和模糊匹配?
MySQL 默认的 LIKE '%关键词%' 在大数据量下会全表扫,而且不支持“张三丰”匹配“张三”。InnoDB 的全文索引(FULLTEXT)对中文基本无效——它按空格切词,而中文没空格。
简单有效方案:用 CHARACTER SET utf8mb4 + COLLATE utf8mb4_unicode_ci,配合 LIKE 前缀匹配(WHERE name LIKE '张三%')加 INDEX,再补一个轻量级的 name_pinyin 字段存拼音首字母(如 "zs"),用于快速筛选。
- 建表时必须指定
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,否则中文排序和比较出错 -
name字段加INDEX,但LIKE '%张%'依然无法用索引,优先考虑前端输入防抖 + 后端限制最小搜索长度(≥2 字) - 真要高级搜索(同音、错别字),别硬刚 MySQL,导出到 Elasticsearch 或用 MeiliSearch 做外挂
事务里更新名片同时发通知,为什么偶尔丢消息?
典型写法是在同一个事务里 INSERT 通知记录 + UPDATE 名片状态,看似原子。但一旦通知服务不可用,整个事务回滚,名片也改不了——业务语义错了:名片更新是核心,通知只是尽力而为。
正确顺序:先 COMMIT 名片变更,再异步发通知(用消息队列或延迟重试任务)。如果非要在 DB 层解耦,至少用 INSERT INTO notify_queue (...) VALUES (...) 记录待发任务,再由独立消费者拉取执行。
- 禁止在事务内调用外部 HTTP 接口(如发邮件、推微信),网络超时直接卡死事务
-
notify_queue表必须有status(pending/failed/sent)和retry_count,不然失败就永久丢失 - 如果用 MySQL 8.0+,可考虑
INSERT ... ON DUPLICATE KEY UPDATE防重复插入,但别依赖它做幂等——逻辑幂等要在应用层判断
最常被忽略的一点:名片里的「个人简介」字段如果允许富文本(带 HTML 标签),入库前必须严格过滤(如用 DOMPurify),否则 textarea 提交一段 <script>...</script>,下次渲染就 XSS。这不是 MySQL 的事,但数据从它过,就得拦住。











