English version · 区块链学习导航 · 上一篇
区块链学习 · 延伸文章 BCX018

两种查询在模拟阶段返回相同记录,验证时却可能保护不同事实。已捕获的字典序范围可以发现保护区间内新增的键;富查询证据包可以保护已捕获结果键的版本,却未必发现另一个新满足选择器的记录。
因此,有用的问题不只是“查询返回了什么”,而是模拟器捕获了哪些证据、哪些较早的有效写入会影响比较状态,以及这些证据究竟能够检查哪项验证条件。
本文提供虚构目录记录和完整证据包。你将计算验证结果,解释一个通过模型检查但计数已过期的报告,并区分真正的部分范围见证与只是看过一行的链码循环。二十个案例和320次有限比较支持该工作表;没有运行Fabric节点、CouchDB查询、链码或账本提交。
选择适合你的阅读路线
本篇目录
- 1. 按给定含义读取数据集
- 2. 检查两种证据包
- 3. 先建立验证状态,再执行检查
- 4. 主要对照:验证前插入item:a2
- 5. 删除捕获键与同值替换
- 6. 端点与范围外变更测试
- 7. 空结果未必表示没有依赖
- 8. 给定的部分见证保护一个捕获前缀
- 9. 节点批量响应可能比循环看见的捕获更多
- 10. 无效前序交易与后续写入改变解释
- 11. 复现有限检查并记录限制
- 12. 练习与参考答案
- 来源与后续阅读
- 要理解范围查询与富查询的主要对照,阅读第1—4节。
- 要检查版本变化、端点和空结果,阅读第5—7节。
- 要理解部分扫描和关键的节点批量响应区别,请把第8—9节一起阅读。
- 要理解顺序、复现方法并完成自测,继续阅读第10—12节。
先修Fabric背书、排序与验证课程已介绍交易流程。一般性的数据库事务与幻读概念也有独立课程。这里的新任务是检查两种Fabric查询路径产生的具体证据。
1. 按给定含义读取数据集
系统只有一个公开链码命名空间。初始记录为:item:a1的shelf为A、value为10、版本为(40,1);item:a3的shelf为A、value为30、版本为(40,2);item:b1的shelf为B、value为50、版本为(40,3)。版本是给定的身份标记,与应用值分开。
完整字典序范围是[item:a, item:b),即包含不小于item:a且小于item:b的键。另一种富查询选择器是{“selector”:{“shelf”:”A”}}。在本数据集中,两者都返回item:a1和item:a3。键区间与JSON字段条件是不同标准;这里只因给定数据布局而碰巧一致。
两种替代提案都准备写入report:A,内容为count 2。报告键位于扫描范围之外,也没有额外读取依赖。这两个证据包代表替代历史,不是必须一起提交的两项提案。富查询写入特意展示一种不安全的依赖假设,不是推荐这种部署设计。
其他交易检查和应用授权均假设成功,MVCC验证启用。键唯一,端点是有界非空ASCII字符串,练习使用原始键与版本范围证据。不包含私有数据、分页、哈希摘要比较、查询错误、多命名空间或链码不确定性。
完整范围见证确实在总查询上限以内到达迭代器耗尽。较早写入使用新的版本高度。每个前序交易是否有效单独给出;只有有效的前序写入进入比较状态。
2. 检查两种证据包
已耗尽范围证据包没有额外普通点读。其RangeQueryInfo记录StartKey=item:a、EndKey=item:b、ItrExhausted=true,以及有序键版本对:item:a1对应(40,1),然后item:a3对应(40,2)。
富查询证据包把这两对键和版本记录在普通Reads列表中,没有RangeQueryInfo。选择器解释模拟时如何选中记录,但该包没有一个在验证时重新检查选择器完整匹配集合的范围见证。
这些都是给定的已捕获证据包。不要依据你认为应用循环“应该读过什么”,重建另一个包。后文会说明,节点侧响应处理可能使这种推断出错。
对范围见证,应记录起点、实际记录的终点、耗尽标志和准确有序键版本列表。对普通读取,应记录每个键及版本。把拟写入报告单独列出:写入提案是预期输出,不是输入集合保持不变的证据。
固定版本v2.5.16的查询执行器支持这一区别:范围结果和富查询结果填充不同依赖结构。本文模拟相关公开数据路径,不覆盖所有查询API或摘要表示。
3. 先建立验证状态,再执行检查
从给定已提交状态出发,按顺序叠加前序有效插入、更新和删除。前序无效交易的拟写入不会进入比较状态。在虚构区块内,即使新写入重复旧应用值,也使用新的版本身份。
在所建模的命名空间内,先检查普通捕获键的版本。捕获键缺失或版本不匹配,产生MVCC_READ_CONFLICT。然后,把每个范围在验证状态下的键版本序列与捕获序列比较;不一致则产生PHANTOM_READ_CONFLICT。
对已耗尽范围,使用包含起点、不包含原始终点的区间。对未耗尽见证,则包含其记录的结束键。我们会具体计算第二种情况,而不是从查询原始参数猜测区间。
只有给定检查全部通过,证据包才通过模型中的状态验证阶段。在其他检查成功的附加假设下,其拟写报告可以在模型中应用。这是教学结果,不是观察到真实提交。
比较计数或应用值,都不能代替这些检查。值相同但版本更新,仍可能使依赖失效;两组不同键也可能具有相同记录数。
4. 主要对照:验证前插入item:a2
一个前序有效交易插入item:a2,shelf为A、value为20,新版本为(41,0)。原来的a1、a3版本不变。在查询提案的验证位置,已经有三条shelf A记录。
完整范围包的验证状态序列为:a1对应(40,1),a2对应(41,0),然后a3对应(40,2)。与捕获序列a1、a3比较,第一对匹配,但下一项当前键是a2,而见证期待a3。范围检查产生PHANTOM_READ_CONFLICT,其count 2报告不应用。
富查询包的普通读取检查只询问a1是否仍为(40,1)、a3是否仍为(40,2),两项均匹配。包中没有依赖要求检查新增a2是否也满足shelf=A。因此,该包通过模型状态检查,拟写的count 2报告可以应用,尽管已有三条匹配记录。
这里缺少的是结果集合保护,而不是富查询完全没有任何验证。返回键仍有版本依赖。如果把富查询说成“完全不检查”,就会错误预测下一节结果。
官方CouchDB指导提醒,匹配集合可能变化,因此富查询与账本更新组合使用存在风险。虚构报告把这个限制具体展示出来;添加查询索引本身不会补上缺失的验证条件。
5. 删除捕获键与同值替换
重置到原始状态。前序有效交易删除item:a3。范围包期待的第二个键缺失,因此产生PHANTOM_READ_CONFLICT。富查询包也失败,但它对a3的普通读取依赖产生MVCC_READ_CONFLICT。
再次重置。把item:a1重新写成同样的shelf A和value 10,但使用新版本。范围仍含两个键,可见应用值也没变,然而a1的记录版本已经不匹配。
因此,纯范围包产生PHANTOM_READ_CONFLICT,富查询包产生MVCC_READ_CONFLICT。错误码不同,是因为依赖被捕获在不同位置,不表示只有一种查询发现了变化。
另一次重置中,先有效删除a3,再有效插入a2。匹配数量仍为二,但身份不同。范围发现序列变化;富查询发现其捕获的a3已经不存在。计数回到二,不能挽救任何一个提案。
如果真实证据包同时包含普通读取和范围证据,第一个失败检查取决于完整证据包及相关验证顺序。这里故意用纯范围与纯富查询包隔离原因,使答案能够复现。
6. 端点与范围外变更测试
把item:b1的value从50改成51,既在完整区间之外,也不属于富查询包捕获的键。两个给定包都通过模型检查。该结论只针对这些依赖,不声称b1永远不影响其他应用规则。
插入一个准确等于item:b的键。已耗尽范围的上端点不包含在内,所以新增键不进入比较序列。在给定假设下,完整范围仍然有效。
改为插入准确等于item:a的键。下端点包含在内,因此在a1前新增一项结果,完整范围产生PHANTOM_READ_CONFLICT。
这两项故意测试准确端点,而不是模糊的“靠近边界”。用字符串前缀思维,或把两端都当作包含,会得到错误结果。所有字符串均按给定的简单字典序处理。
还要把键成员资格与shelf字段分开。范围条件取决于键顺序。这里新增的下端点记录给定为shelf A;即使改成另一shelf,只要键仍在区间内,也不会因此从范围比较中消失。
7. 空结果未必表示没有依赖
另用一个已耗尽范围[item:c, item:d),初始没有任何键。证据仍记录该区间、耗尽状态和空结果列表。前序有效插入item:c2后,验证状态结果不再为空,因此范围见证产生PHANTOM_READ_CONFLICT。
再用一个独立的shelf C富查询选择器,初始也为空。其给定包没有捕获结果键读取,也没有范围见证。同一条新增C记录不会使空普通读取列表出现不匹配。模型状态阶段通过,但拟写count 0报告已经不再描述匹配集合。
因此,空结果可能编码一个捕获区间内受到保护的“不存在”,也可能仅仅意味着富查询包没有返回键依赖。必须检查证据结构,不能从数字零推断保护范围。
这些例子没有添加普通缺失键读取或自定义应用约束。如果存在,它们就是需要另行评估的额外证据。结论只针对给定的两个包。
8. 给定的部分见证保护一个捕获前缀
考虑另一包,其RangeQueryInfo为StartKey=item:a、EndKey=item:a1、ItrExhausted=false,仅捕获a1对应(40,1)。这个准确见证直接作为输入给出,不是根据链码循环显示一行来推断。
对该未耗尽见证,记录的终点a1包含在内。保护区间从item:a一直到item:a1,两端包含。原始查询可能请求更长范围,但这份捕获证据不认证整个范围。
在记录终点之后插入item:a2,前缀序列不变,因此该包通过。其拟写输出明确叫captured_prefix_count 1,不是完整的shelf A计数。若把它说成“总共只有一条”,即使没有并发变化,也已超出证据。
改为插入item:a0,它位于a1之前、保护区间之内,新增结果导致PHANTOM_READ_CONFLICT。如果把a1同值重写为新版本,也会失败,因为包含在内的结束键版本改变了。
部分结果既不是全范围保护,也不是毫无保护,而是有准确区间和版本边界。下一节说明,看到一行应用结果,并不能独自证明真正捕获的就是这个区间。
9. 节点批量响应可能比循环看见的捕获更多
使用一个贴近源码相关分支的探针:初始待发送结果为空、不分页、MaxResultLimit=1、totalReturnLimit至少为2,且没有迭代器错误。这些刻意很小的参数是教学输入,不是生产默认值。
节点响应构造器先消费a1并将其排入待发送列表。随后,它在决定返回前一批结果之前,已经消费了a3。此时a1可以交给链码,而a3已经被模拟器捕获,并缓冲等待后续响应。
该探针的捕获范围终点为a3,ItrExhausted=false,列表包含a1和a3。它不同于第8节的单键见证,尽管应用到目前为止只收到a1。
现在插入a2。它落在延伸至a3的捕获区间内,所以探针的范围比较产生PHANTOM_READ_CONFLICT。仅因为链码表面上调用过一次Next就预测通过,是使用了错误证据包。
固定版本响应构造器解释了这个缓冲边界。本文不预测所有部署的批量大小或总上限。实用规则是检查实际捕获的查询证据,包括记录终点与耗尽标志,不能把应用可见消费量等同于节点侧迭代器消费量。
10. 无效前序交易与后续写入改变解释
重置到完整基线见证。一个排在前面的提案准备插入a2,但被标记为无效。它的写入不进入比较状态,完整范围仍看到原版本的a1、a3,因此通过。仅排在查询之前还不够;该写入必须有效,才影响本次计算。
再把主要案例的有效插入顺序反过来。让完整查询先验证,此时只有a1、a3匹配,count 2报告可以应用。随后,一个其他条件均有效的纯写入交易插入a2。两者完成后,匹配计数为三,存储报告仍为二。
这没有矛盾。范围检查保护的是给定观察在其验证位置上的一致性,不会建立永久锁,不保证未来不能新增记录,也不会自动维护实时聚合。
后续插入有效,是关于该纯写入交易及其他检查成立的给定假设。练习不证明任意后续交易都必须通过,而是区分验证时一致性与无限期的报告新鲜度。
因此,有用的报告应保留相关观察或验证上下文。没有时间或状态边界的单一数字,容易被理解成比原证据更强的结论。
11. 复现有限检查并记录限制
二十个指定案例包括:未变化证据包、主要插入对照、删除、同值新版本、范围外更新、完整范围两端点、三个部分范围变体、两个空结果变体、无效前序交易,以及计数不变但成员替换。
本地检查器把有序序列验证器与另行表达的成员集合及版本条件比较。它为三个键各赋四种模式,生成64个有界状态,再让五种证据包分别检查每个状态,总计64乘5,即320次比较。反向顺序断言与批量响应探针是另外的检查。
一致性只检查这些有限表达的内部相容性,不是执行Fabric验证器,也不是独立实现的一致性认证。没有真实CouchDB查询或提交,不能据此推断省略的私有数据、哈希摘要、分页或无界端点行为。
来源包把十三个文件固定到Fabric v2.5.16,包括查询捕获、响应构造、范围比较、合并迭代器及随仓库固定的shim接口。这样可以检查实现边界,而不用假设所有未来版本都一样。
工作表应保留查询条件、普通Reads、每个捕获范围的起点/终点/耗尽标志/列表、前序有效变化、比较序列、第一个失败检查及拟写结果。具备这些列,读者才能针对准确步骤提出不同意见,而不是泛泛争论“MVCC是否安全”。
12. 练习与参考答案
- 新增a2满足shelf A,而a1、a3版本不变。哪个包拒绝它?
- a1以新版本重写为value 10,是否保全两个包?
- 为什么插入a2能通过单键部分见证,却不能通过批量探针?
- 空的已耗尽范围是否没有东西可验证?
- 如果前面的插入本身无效,完整范围仍然无效吗?
- 有效的完整范围报告,会因之后的有效插入而过期吗?
答案:1. 完整范围拒绝变化序列;给定富查询包通过捕获键检查。2. 不会,两者分别因范围依赖和普通读取依赖失败。3. 记录终点不同,分别是a1和a3,而且未耗尽终点包含在内。4. 不是,记录区间内新增键会否定空见证。5. 不会,无效写入被排除在比较状态之外。6. 会,验证不会在后续写入后维护报告。
延伸问题:一张只显示“返回两行”的截图缺少什么证据?它缺少查询类型、捕获键版本、区间和耗尽状态、节点捕获行为,以及前序有效写入。没有这些输入,验证结果无法确定。
来源与后续阅读
来源审查日期为2026年10月13日。实现及相应文档固定为Hyperledger Fabric v2.5.16,不声称它是最新发行版。
要回顾更广泛的交易流程,可返回Fabric背书、排序与验证。本文的结论保持狭义:先确定捕获查询包保护什么,再在给定验证位置准确比较那些证据。
