数据持久化与缓存 / 技术笔记

数据一致性与持久化

从一次订单写入开始,理解多个步骤如何一起成功,以及失败和重试应该怎样处理。

内容章节
6 节
阅读重点
事务与可靠性
示例语言
SQL / TypeScript

一次下单可能同时包含创建订单、扣减库存、记录支付和发送通知。代码只能确定调用顺序,多个步骤仍可能在中途失败。

文本示意

text

订单已创建库存扣减失败支付消息没有发出

数据一致性讨论的,就是系统遇到失败、并发和重试时,业务事实是否仍然合理。

持久化不仅是把数据写进去,还要定义失败以后系统处于什么状态。

1. 数据一致性到底在一致什么

一致性的目标是让系统始终满足重要的业务规则,各处数据可以根据业务要求同步到合适状态。

文本示意

text

库存不能小于 0一笔支付只能生成一个有效订单订单总额等于订单项金额之和

先写清楚规则,才能判断需要数据库事务、唯一约束,还是跨服务补偿。

2. 事务保证了什么

事务把多条数据库操作看成一个整体。

SQL 示例

sql

START TRANSACTION;
UPDATE inventorySET quantity = quantity - 1WHERE product_id = 42 AND quantity > 0;
INSERT INTO orders(user_id, product_id)VALUES (7, 42);
COMMIT;

中间任何一步失败,都应该回滚。事务适合保护同一个数据库中的紧密操作,但不能自动解决外部支付或消息服务的问题。

3. 强一致和最终一致怎样选择

强一致要求写入完成后立刻读到最新结果。最终一致允许短时间不同步,但系统会经过重试和补偿回到正确状态。

文本示意

text

账户余额:更偏向强一致搜索索引:通常允许最终一致邮件通知:通常允许延迟

选择依据来自错误结果可能造成的损失,以及业务能够接受的同步延迟。

4. 消息队列为什么能解耦

订单服务不必等待邮件、积分和分析系统全部完成。它可以先保存业务事件,再由其他服务消费。

JSON 示例

json

{    "event": "order.created",    "orderId": "order-42",    "occurredAt": "2026-09-11T08:30:00Z"}

队列把同步调用变成可重试的异步处理,但也带来了重复消息、顺序和失败补偿问题。

5. 幂等为什么必须考虑重试

网络超时只说明调用方没有收到结果,服务端可能已经完成处理。此时重试可能让同一请求执行两次。

TypeScript 示例

typescript

await createOrder({    idempotencyKey: "checkout-user7-cart19",    items,});

服务端保存并检查幂等键。相同请求再次到达时直接返回第一次的结果,从而避免重复创建订单。

6. 一次可靠写入的完整过程

一个更可靠的订单流程可以这样组织:

文本示意

text

校验幂等键开启数据库事务创建订单并扣减库存同时保存待发送事件提交事务后台发送事件并重试失败任务消费者按事件 ID 去重

可靠系统会提前设计失败后的发现、重试和恢复方式,并把异常情况纳入正常流程。