保存明确恢复点的订单

PostgreSQLBeginner
立即练习

介绍

PAPER & FORM 销售纸质印刷品和桌面用品。商店即将迁移到另一项服务,店主需要准确知道备份能找回哪些订单。仅仅有一个文件还不够:它必须包含明确恢复点上的每笔订单及其商品明细。

你将下一笔小订单,保存 PostgreSQL 自定义格式备份,再添加另一笔订单,理解它为什么不在备份中。具备基本终端操作能力即可。数据库、工具和网站已经准备好,无需编写 SQL 或安装软件。顾客、价格和订单均为虚构数据,不涉及支付或邮件服务。

在 Original Shop 操作原店,在 Workstation 执行命令。Restored Copy 是下一个实验使用的独立空目标,本单元不要向其中恢复。每个单元都有自己的初始数据。保持所提供的程序和 uploads/ 不变。这是逻辑数据库导出演练,不是完整灾难恢复或时间点恢复(PITR)。

录入必须进入备份的订单

本步骤将创建一笔包含商品明细的真实订单。先打开 Original Shop。蓝色横幅标明原始数据库 shop_source。打开 Explore the collection ↗。商品目录中,Print pair 每件 $18.00,Desk tray 每件 $26.00。打开顶部导航的 Orders,选择 R-101,阅读明细:两件 Print pair 合计 $36.00。选择 Download receipt ↓,阅读保存的文本。它包含编号、顾客、商品、数量和总额。通过 PAPER & FORM 返回首页。

数据库存储结构化记录。这里,orders 保存订单编号和顾客,order_items 保存商品明细行。每条明细都指向所属订单。只保留顾客姓名或总额会丢失商店需要的关联。记录页面与收据读取的是这些真实关联的数据行。

切换到 Workstation。pwd 显示当前目录,ls 列出其中的文件:

pwd
/home/labex/project/shop-backup
ls

你应看到 backups、shopctl 和 uploads。把导出文件保存在 backups/。uploads/packing-note.txt 是无关文件,必须保持不变。逻辑数据库导出不包含数据库之外的文件。

./shopctl 运行当前目录中提供的辅助工具。其 identity 操作显示真实数据库连接。角色是决定权限的数据库账号;主机与端口用于定位数据库服务。执行:

./shopctl identity

找到源库 shop_source,其只读客户端角色为 d09_reader;目标库为 shop_copy,可写角色为 d09_copy,两者都位于 127.0.0.1:5432。共用服务器不代表它们是同一个数据库。副本角色不能连接源库。网站使用另一个可写源库角色。这些是训练中的操作边界,并不能防御拥有系统管理员权限的人。

切换到 Original Shop,打开 Collection,滚动到 Place an order。提交前阅读 Writing to: shop_source · ORIGINAL SHOP。准确填写:

字段 值
Reference R-103
Name Rae
Item Print pair
Quantity 2

选择 Place order ↗。记录页面应显示 R-103、Rae、两件 Print pair,总额 $36.00。这是截止订单,必须进入备份。原店表单会拒绝未知编号和仅供副本使用的编号,不写入记录。在有效且受保护的 cutoff-kept.dump 保存之前提交 R-104,也会返回 Keep the earlier point first,不会写入数据。如果本来要输入 R-103,请回到 Collection 修正编号。这是在保护本演练要求的记录顺序,并非生产商店通常必须等备份完成才能接单。如果已存在的 R-103 填错了顾客、商品或数量,可在 Workstation 仅修正这条指定练习记录:

./shopctl correct source R-103

辅助工具先显示真实目标,再仅把 R-103 改为 Rae / Print pair / 2。它拒绝修正原始基线编号,保留其他订单、后续记录、上传文件和全部归档。这是学员显式执行的纠错,检查不会代为操作。导出前修正并重新阅读记录。如果重复点击后编号已存在,表单会返回 Already recorded;此时打开 Orders 检查已有记录,不要重复提交。

返回 Workstation。records 显示真实关联数据,最后两个数字分别为数量和以分为单位的单价:

./shopctl records source

找到 R-103 | Rae | Print pair | 2 | 1800,三笔订单合计 $98.00。你已添加目标订单,并保留原来的 R-101 和 R-102。

保存一致的自定义格式归档

本步骤将保存三笔已提交的订单。恢复点是导出捕获的数据库状态,不由文件名或修改时间决定。PostgreSQL 的 pg_dump 创建一致快照:即使其他用户正在操作,关联表也取自同一个数据库视图。本演练先完成 R-103,再导出,并等待导出结束后才添加下一笔订单。这种顺序无需比较时钟,就能明确截止点。

留在 Workstation。pg_dump 导出数据库,pg_restore 读取它的归档格式。检查已安装客户端的版本:

pg_dump --version
pg_restore --version

在预置环境中,两者都应报告 PostgreSQL 14,服务器也是 14。较旧的 pg_dump 连接较新服务器可能失败;不要用保存空文件的方式绕过版本错误。本实验已经准备了相互匹配的工具。

选择源库前,再次显示连接:

./shopctl identity

PostgreSQL 连接服务是一组保存的连接设置。提供的 service=shop-source 选择 shop_source 及其只读角色,service=shop-copy 选择独立目标。--dbname 指定该连接。始终显式填写服务名,不要依赖客户端默认值。

--format=custom 创建 PostgreSQL 的压缩归档格式,需要用 pg_restore 处理,而不是普通 SQL 脚本。--file 指定输出文件。--no-privileges 不导出源库的授权。对于自定义归档,pg_dump --no-owner 会被忽略;应在之后运行 pg_restore 时传入 --no-owner 来跳过原所有权。这个恢复选项使目标角色拥有恢复后的对象。下面的命令读取源库,只写入指定的本地备份文件:

pg_dump --dbname=service=shop-source --format=custom --no-privileges --file=backups/cutoff.dump

成功导出通常没有输出。等命令完成后再录入下一笔业务订单。若出现连接或文件错误,检查 pwd、./shopctl identity 和输出路径后重试。重新执行会替换 backups/cutoff.dump,因此只能在源库仍处于目标截止状态时这样做。较晚的导出会捕获较晚的数据。

pg_restore --list 读取归档目录,不导入数据库:

pg_restore --list backups/cutoff.dump

在开头附近找到 Format: CUSTOM、dbname: shop_source 和匹配的数据库/导出客户端版本。继续向下,找到 orders、order_items 以及数据、序列和约束的条目。它们说明归档结构,不能证明业务记录正确;实际恢复并读取记录是更强的证据。

本步骤的检查会把你的实际归档恢复到新建的可丢弃数据库,验证截止订单及其商品关联。它不会恢复 Restored Copy 标签中的现场。保留归档供下一步使用。

进入下一步前,阅读检查结果并保存已经验证的归档。cp 把文件复制为另一个名称;chmod a-w 移除所有用户的写权限,防止意外使用 pg_dump --file 覆盖这两个文件:

cp backups/cutoff.dump backups/cutoff-kept.dump
chmod a-w backups/cutoff.dump backups/cutoff-kept.dump

仅在备份检查通过后执行保护。此后直接向任一受保护文件导出会报 Permission denied,而不会替换恢复点。如果意外删除原文件名,cp backups/cutoff-kept.dump backups/cutoff.dump 可以取回原来的字节。保留文件是应对普通失误的第二份本地副本,并不是异地灾备。

区分后续订单与已保存恢复点

本步骤将观察源库继续变化,而归档停留在较早状态。切换到 Original Shop,打开 Collection,写入前阅读 Writing to: shop_source · ORIGINAL SHOP。提交:

字段 值
Reference R-104
Name Sol
Item Desk tray
Quantity 1

新记录总额为 $26.00。打开 Orders,确认 R-101、R-102、R-103 和 R-104 都在。R-104 在 pg_dump 完成后提交,因此不属于 backups/cutoff.dump。备份不是持续接收订单的实时连接。现在不要重新导出并覆盖截止归档。

在 Workstation 再次读取源库:

./shopctl records source

输出现在包含 R-104 | Sol | Desk tray | 1 | 2600,总额为 $124.00。源店仍然可用;你没有为了制造恢复演练而破坏业务数据。再次列出归档,仍会看到原来的结构:

pg_restore --list backups/cutoff.dump

归档检查只把它恢复到可丢弃的测试数据库。预期包含 R-101 至 R-103,不包含 R-104。这证明的是恢复点,而不是仅确认文件存在。本单元保持 Restored Copy 为空。

如果填错 R-104,./shopctl correct source R-104 会显示源库,并仅把该已有练习订单修正为 Sol / Desk tray / 1,保留所有更早记录。表单会拒绝未知编号,因此修正编号后重新提交即可。

如果意外删除或替换了 cutoff.dump,应从保留的早期字节恢复,而不是重新生成未来快照。在 Workstation,chmod u+w 赋予所有者对这个文件的写权限,随后用 cp 取回内容,再用 chmod a-w 重新保护:

chmod u+w backups/cutoff.dump
cp backups/cutoff-kept.dump backups/cutoff.dump
chmod a-w backups/cutoff.dump

如果文件已被删除,跳过第一条命令,直接使用保留副本。随后重新运行归档检查。不要删除 R-104 或倒退源库:必须保留后续业务记录。如果较早恢复点的每一份副本都已丢失,新的逻辑导出无法重建过去。因此,前一步先检查并保留受保护副本,再允许源库进入后续状态。下一个独立实验会提供同一截止点的归档,让你专注练习安全恢复。

总结

你创建了真实订单,导出了一份一致的 PostgreSQL 自定义格式归档,并区分了已保存恢复点与源店后续订单。归档检查在可丢弃数据库中验证了实际恢复后的数据关系。下一个独立实验将把已保存状态打开为可用的商店副本。