MySQL仅存储文件路径和元数据,不直接处理文件上传;应用需将文件存至磁盘或对象存储,并将路径、大小、哈希等信息分字段写入数据库,确保安全过滤、事务一致性及索引优化。

MySQL 本身不存文件,只存路径和元数据
MySQL 不是文件服务器,LOAD_FILE() 和 SELECT ... INTO DUMPFILE 这类函数只用于服务端本地文件读写,且依赖 secure_file_priv 配置,无法直接接收客户端上传的二进制文件。所谓“文件上传记录”,本质是:应用层把文件存到磁盘或对象存储(如 S3、MinIO),再把路径、大小、哈希、上传时间等信息写入 MySQL 表。
建表时必须区分「路径字段」和「元数据字段」
常见错误是只建一个 file_path 字段,后续查类型、校验完整性、做清理都困难。应拆开设计:
-
file_path:绝对路径或相对路径(推荐用相对路径 + 应用统一前缀,便于迁移) -
file_name:原始文件名(含扩展名),用于前端下载时还原 -
file_size:BIGINT,单位字节,避免用 VARCHAR 存 “1.2MB” -
file_hash:CHAR(64),存 SHA256,防重复上传或校验损坏 -
mime_type:VARCHAR(100),从请求头或文件头解析,不是靠后缀判断 -
uploaded_at:DATETIME(3),带毫秒,避免并发上传时间戳冲突
路径写入前必须做安全过滤和长度限制
用户可控的路径字段(比如前端传来的 save_path)若直接拼进 SQL 或写入磁盘,极易触发路径遍历(../../../etc/passwd)或长路径导致系统调用失败。实操要点:
- 用
basename()或正则/[^a-zA-Z0-9._\-]+/g清洗文件名,禁止/、..、控制字符 - 路径拼接由服务端生成,例如:
uploads/{date:Ymd}/{uuid4()}.{ext},不信任任何客户端传入的路径片段 -
file_path字段在 MySQL 中定义为VARCHAR(512)足够,超长说明逻辑异常,应拦截而非截断 - 如果用 NFS 或挂载目录,确保 MySQL 进程对目标路径有读权限(
SELECT LOAD_FILE()才能读),但写权限必须仅限应用进程
查询时别用 LIKE 匹配路径,用前缀索引+独立字段
有人习惯在 WHERE file_path LIKE '%report_2024%',这会强制全表扫描,且无法利用索引。真正高效的方式是:
- 提取业务维度到独立列:比如
doc_type ENUM('invoice', 'contract', 'scan')、year_month CHAR(6)(值如'202407') - 对
file_name建前缀索引:INDEX idx_name (file_name(32)),覆盖大多数真实文件名长度 - 需要按目录查?就不要把完整路径塞进一列,改用
storage_dir VARCHAR(128)+file_name两列联合查询 - 避免在 SQL 里用
SUBSTRING_INDEX(file_path, '/', -1)提取文件名——这无法走索引,应在写入时就拆好










