1626 字
8 分钟
图生图场景:数据库表设计与异步生成流程

一、整体架构#

假设用户上传一张照片,输入提示词“把照片变成动漫风格”,要求生成 4 张图片。

flowchart TD
A["① 前端提交请求:原图、提示词、生成参数"]
B["② 后端上传原图到 MinIO,获取 object_key"]
C["③ 创建生成任务并写入数据库,状态为 PENDING"]
D["④ 异步调用 AI 模型,状态更新为 PROCESSING"]
E["⑤ 生成图片并上传 MinIO,每张图片生成一个 object_key"]
F["⑥ 保存图片记录,更新任务状态为 SUCCESS 或 FAILED"]
A --> B
B --> C
C --> D
D --> E
E --> F
M[("MinIO 对象存储")]
DB[("MySQL / PostgreSQL")]
B -. 保存原图 .-> M
C -. 保存任务 .-> DB
E -. 保存生成图片 .-> M
F -. 保存结果和任务状态 .-> DB

二、数据库具体怎么设计?#

我会设计三张核心表,分别管理图片资源、生成任务和生成结果。

1. 图片资源表 image_asset#

负责管理 MinIO 中的图片。

字段作用
id图片资源 ID
user_id所属用户
bucket_nameMinIO 存储桶名称
object_key图片在 MinIO 中的唯一标识
mime_type图片格式
file_size图片大小
width、height图片尺寸
created_at创建时间

例如,数据库保存:

id: 10001
bucket_name: ai-images
object_key: users/2001/original/abc.png

真正的图片文件在 MinIO 里,数据库只记录如何找到它。

2. 生成任务表 image_generation_task#

负责管理一次图生图任务。

字段作用
id任务 ID
task_no业务任务编号
user_id发起任务的用户
source_image_id原图 ID,关联图片资源表
prompt用户提示词
model_name使用的模型
model_params模型参数,使用 JSON 存储
status任务状态
error_code、error_message失败信息
created_at、finished_at创建和结束时间

例如:

task_no: TASK_5001
source_image_id: 10001
prompt: 把照片变成动漫风格
model_name: image-model-v1
status: PROCESSING

这里用 source_image_id 关联图片资源表,而不是直接存一大串图片数据或依赖临时 URL。

3. 生成结果表 image_generation_result#

负责记录每次任务生成的图片。

字段作用
id结果记录 ID
task_id对应的任务 ID
image_id生成图片 ID,关联图片资源表
result_index第几张结果图
created_at创建时间

如果任务 TASK_5001 生成 4 张图片,就写入 4 条结果记录,每条关联一个 image_id。

这样就形成了:

生成任务表

TASK_5001 · 原图 ID = 10001

生成结果表

4 条记录,分别关联 4 个 image_id

图片资源表 → MinIO

根据各自的 object_key 找到实际图片文件

三、任务执行过程中需要考虑什么?#

这是面试官很容易继续追问的部分。

第一,为什么要异步处理?

图片生成耗时可能比较长。如果一直让 HTTP 请求等待,容易超时。因此可以创建任务后立即返回 task_no,通过消息队列交给后台 Worker 处理,前端再通过轮询或 WebSocket 查询任务进度。

第二,模型调用失败怎么办?

任务状态可以设计为:

PENDING → PROCESSING → SUCCESS / FAILED

如果调用超时,不能直接认定模型没有执行成功。应先查询模型任务状态;如果模型支持幂等请求,还可以使用稳定的请求标识重试,避免重复生成。

第三,上传 MinIO 和写数据库不在同一个事务中怎么办?

MinIO 和 MySQL 通常不能通过普通数据库事务实现原子提交。因此要考虑失败补偿:

  • 图片上传成功、数据库写入失败:清理孤立文件,或者由定时任务扫描回收。
  • 图片生成成功、结果记录失败:保留任务信息并重试保存结果,避免重复调用模型。
  • 任务失败:记录错误原因和重试次数,按策略重试或标记失败。

第四,如果涉及扣费怎么办?

单独设计计费流水,并通过幂等键避免重复扣费。不要仅凭任务接口超时就再次扣款,也不要简单地把扣费操作和图片生成状态混在一张表里。

四、完整面试口播#

下面这段可以直接作为面试回答来练习。

如果让我设计图生图业务的数据库,我会从图片存储、任务管理和结果管理三个方面考虑。

首先,图片本身会放在 MinIO 这样的对象存储中,数据库不直接存储图片二进制,而是保存图片 ID、Bucket、Object Key、文件类型和大小等元数据。

数据库方面,我会设计三张核心表。

第一张是图片资源表,负责管理原图和生成图在 MinIO 中的存储位置。

第二张是生成任务表,记录用户 ID、原图 ID、提示词、模型名称、模型参数、任务状态和错误信息等。模型参数可以使用 JSON 存储,以适应不同模型的参数差异。

第三张是生成结果表,记录任务 ID 和生成图片 ID 的关联。因为一次图生图任务可能生成多张图片,所以任务和结果是一对多的关系。

整个流程是:用户上传原图,后端将图片保存到 MinIO,并在数据库记录图片信息;然后创建生成任务,将任务交给后台 Worker 异步处理;Worker 调用 AI 模型,拿到生成结果后将图片上传到 MinIO,再保存图片资源和结果记录,最后更新任务状态。

另外,我还会考虑异常处理。如果模型调用超时,需要先判断模型是否已经执行成功,再决定是否重试;如果 MinIO 上传成功但数据库写入失败,需要进行补偿或清理,避免产生孤立文件。如果涉及用户扣费,还需要独立的计费流水和幂等机制,避免重复扣费。

这样既能管理图片资源,也能支持多图生成、任务查询、失败重试和后续扩展。

你只需要记住这条主线:

用户上传图片 → MinIO 保存文件 → 图片表记录元数据 → 任务表记录生成请求 → Worker 调用模型 → MinIO 保存结果 → 结果表关联图片 → 更新任务状态。

相关文章#

图生图场景:数据库表设计与异步生成流程
https://blog.xqcherry.top/posts/interview/scenarios/image-to-image-database-design/
作者
xqcherry
发布于
2026-10-22
许可协议
CC BY-NC-SA 4.0