[{"data":1,"prerenderedAt":1580},["ShallowReactive",2],{"post:\u002Fposts\u002Fswdesign\u002Fsw-design-notes-15":3,"posts:ordered":1278},{"id":4,"title":5,"body":6,"category":1260,"cover":1261,"date":1262,"description":1263,"extension":1264,"featured":1265,"meta":1266,"navigation":1267,"path":1268,"seo":1269,"series":1270,"seriesOrder":1271,"stem":1272,"tags":1273,"__hash__":1277},"posts\u002Fposts\u002FswDesign\u002Fsw-design-notes-15.md","软件分析与设计笔记 15：非功能需求：把「快、稳、安全」变成数字",{"type":7,"value":8,"toc":1229},"minimark",[9,16,25,30,33,46,56,60,126,133,140,144,147,150,155,158,229,236,240,247,346,353,357,360,436,440,451,458,466,470,480,487,490,500,504,508,511,514,540,543,597,601,608,611,622,628,632,636,642,650,653,683,689,693,696,726,729,767,773,780,784,788,794,848,855,862,866,877,881,907,910,913,940,943,992,995],[10,11,12],"blockquote",{},[13,14,15],"p",{},"这是我在学习软件分析与设计时整理的系列笔记。概念部分是我按自己的理解写的，示例与图示都是自己编、自己画的。理解有偏差的地方欢迎指出。",[10,17,18],{},[13,19,20,24],{},[21,22,23],"strong",{},"贯穿案例","：片区家电维修派单系统。前面几篇都在说「做什么」，这一篇补上「做得多好」。",[26,27,29],"h2",{"id":28},"_0-系统要快害了多少项目","0 「系统要快」害了多少项目",[13,31,32],{},"需求文档里写着「系统响应要快」。这句话最后会变成三种结局：",[34,35,36,40,43],"ul",{},[37,38,39],"li",{},"开发觉得已经够快，用户觉得慢 —— 因为没有标准；",[37,41,42],{},"上线后才发现要支持的并发量是估算的十倍 —— 因为没估过规模；",[37,44,45],{},"为了「快」把架构做得极复杂，结果大部分是白做的 —— 因为没有说不快会怎样。",[13,47,48,51,52,55],{},[21,49,50],{},"非功能需求（non-functional requirement, NFR）"," 要解决的正是这个问题：把「快、稳、安全」翻译成",[21,53,54],{},"可测量、可验收的数字","。其中最常见的一类，就是性能需求（performance requirement）。",[26,57,59],{"id":58},"_1-它和功能需求的区别","1 它和功能需求的区别",[61,62,63,78],"table",{},[64,65,66],"thead",{},[67,68,69,72,75],"tr",{},[70,71],"th",{},[70,73,74],{},"功能需求",[70,76,77],{},"非功能需求",[79,80,81,93,104,115],"tbody",{},[67,82,83,87,90],{},[84,85,86],"td",{},"回答",[84,88,89],{},"系统做什么",[84,91,92],{},"系统做得多好",[67,94,95,98,101],{},[84,96,97],{},"本例例子",[84,99,100],{},"工程师可以现场申请配件",[84,102,103],{},"申请提交在派单高峰时段 2 秒内完成",[67,105,106,109,112],{},[84,107,108],{},"验收方式",[84,110,111],{},"按用例走一遍",[84,113,114],{},"按指标测量",[67,116,117,120,123],{},[84,118,119],{},"出问题的时机",[84,121,122],{},"一眼能看出来",[84,124,125],{},"上线后高负载时才暴露",[13,127,128,129,132],{},"最后一行是关键：",[21,130,131],{},"非功能缺陷往往要到真实压力下才暴露，而那时改动的代价最高","。所以它必须在需求阶段就被量化。",[13,134,135],{},[136,137],"img",{"alt":138,"src":139},"非功能需求的三张容量表与两类质量要求：三张表分别是用户量表、业务交易量表、数据量表，各自列出分类与规模；下方是安全需求与可靠性需求各自要写清的内容","\u002Fimages\u002Fsw-design-notes-15-nfr-volume.svg",[26,141,143],{"id":142},"_2-性能三个量决定一切","2 性能：三个量决定一切",[13,145,146],{},"聊性能时最容易跑偏到「用什么技术」。其实在技术选型之前，要先回答三个规模问题 —— 也就是三张表。",[13,148,149],{},"贯穿案例的规模先摆出来（一个城市、6 个片区、40 名工程师的试点）：",[151,152,154],"h3",{"id":153},"_21-用户量表user-volume-table","2.1 用户量表（user volume table）",[13,156,157],{},"有多少种使用者、各有多少人。注意区分「注册用户」和「同时在线用户（concurrent user）」——后者才是压力的来源。",[61,159,160,173],{},[64,161,162],{},[67,163,164,167,170],{},[70,165,166],{},"使用者",[70,168,169],{},"总量",[70,171,172],{},"同时在线（峰值）",[79,174,175,186,197,208,219],{},[67,176,177,180,183],{},[84,178,179],{},"客户",[84,181,182],{},"约 12 万（一年累计）",[84,184,185],{},"约 300（早 9 点报修高峰）",[67,187,188,191,194],{},[84,189,190],{},"客服",[84,192,193],{},"8",[84,195,196],{},"8（全员在线）",[67,198,199,202,205],{},[84,200,201],{},"工程师",[84,203,204],{},"40",[84,206,207],{},"约 30（其余在路上）",[67,209,210,213,216],{},[84,211,212],{},"仓管",[84,214,215],{},"6",[84,217,218],{},"4",[67,220,221,224,226],{},[84,222,223],{},"片区经理",[84,225,215],{},[84,227,228],{},"3",[13,230,231,232,235],{},"注意这张表最有价值的地方：",[21,233,234],{},"「同时在线」这一列和「总量」差了两三个数量级","。如果按 12 万客户来设计并发，架构会贵得离谱；如果按 300 来设计，才是对的。",[151,237,239],{"id":238},"_22-业务交易量表business-transaction-volume-table","2.2 业务交易量表（business transaction volume table）",[13,241,242,243,246],{},"每种操作一天发生多少次。这张表的价值在于",[21,244,245],{},"暴露各操作之间的数量级差异","。",[61,248,249,265],{},[64,250,251],{},[67,252,253,256,259,262],{},[70,254,255],{},"操作",[70,257,258],{},"日均",[70,260,261],{},"峰值（单小时）",[70,263,264],{},"倍数",[79,266,267,281,295,309,320,333],{},[67,268,269,272,275,278],{},[84,270,271],{},"客户查工单进度",[84,273,274],{},"3 600",[84,276,277],{},"900",[84,279,280],{},"6×",[67,282,283,286,289,292],{},[84,284,285],{},"客户提交报修",[84,287,288],{},"400",[84,290,291],{},"90",[84,293,294],{},"5×",[67,296,297,300,303,306],{},[84,298,299],{},"客服看排期",[84,301,302],{},"800",[84,304,305],{},"160",[84,307,308],{},"4×",[67,310,311,314,316,318],{},[84,312,313],{},"客服派单",[84,315,288],{},[84,317,291],{},[84,319,294],{},[67,321,322,325,327,330],{},[84,323,324],{},"工程师回填工单",[84,326,288],{},[84,328,329],{},"120",[84,331,332],{},"7×",[67,334,335,338,341,344],{},[84,336,337],{},"库存查询（含外部接口）",[84,339,340],{},"500",[84,342,343],{},"150",[84,345,332],{},[13,347,348,349,352],{},"这里有个关键观察：",[21,350,351],{},"「查进度」的量是「派单」的 9 倍","。如果两者用同一套设计（比如都走同一条重查询链路），查询会把派单拖慢。而派单是业务核心 —— 这就是为什么值得为查询单独做缓存或读库分离。",[151,354,356],{"id":355},"_23-数据量表data-volume-table","2.3 数据量表（data volume table）",[13,358,359],{},"每种数据一年增长多少、要保留多久。它决定的是存储、索引和归档方案，而不是接口响应。",[61,361,362,378],{},[64,363,364],{},[67,365,366,369,372,375],{},[70,367,368],{},"数据",[70,370,371],{},"年增量",[70,373,374],{},"保留要求",[70,376,377],{},"说明",[79,379,380,394,408,422],{},[67,381,382,385,388,391],{},[84,383,384],{},"工单",[84,386,387],{},"10 万条",[84,389,390],{},"5 年（法规）",[84,392,393],{},"5 年后约 50 万条，可归档",[67,395,396,399,402,405],{},[84,397,398],{},"配件消耗",[84,400,401],{},"30 万条",[84,403,404],{},"5 年",[84,406,407],{},"随工单归档",[67,409,410,413,416,419],{},[84,411,412],{},"客户档案",[84,414,415],{},"12 万条",[84,417,418],{},"长期",[84,420,421],{},"含手机号，属敏感数据",[67,423,424,427,430,433],{},[84,425,426],{},"工单状态流水",[84,428,429],{},"200 万条",[84,431,432],{},"1 年",[84,434,435],{},"用于分析，1 年后可汇总",[151,437,439],{"id":438},"_24-增长率的启示","2.4 增长率的启示",[13,441,442,443,446,447,450],{},"这三张表的另一个作用是",[21,444,445],{},"引出增长率","：现在的量和三年后的量可能差好几倍。",[21,448,449],{},"只按今天的规模设计，等于提前锁定一次重构"," —— 而让系统在规模增长时仍保持表现，正是可扩展性（scalability）要解决的问题。",[13,452,453,454,457],{},"本例的增长率很明确：王姐说要推到另外 5 个片区，也就是",[21,455,456],{},"三年内规模可能放大 6 倍","。这一句就决定了：",[34,459,460,463],{},[37,461,462],{},"数据表要一开始就按分片区设计（否则后期要迁移）；",[37,464,465],{},"「单城市 300 并发」这个数字不能写死进架构假设。",[26,467,469],{"id":468},"_3-峰值与均值","3 峰值与均值",[13,471,472,473,476,477,246],{},"估这三张表时，必须同时给出两个数：",[21,474,475],{},"均值","和",[21,478,479],{},"峰值（peak load）",[13,481,482,483,486],{},"峰值和均值的差距常常是十倍以上：本例的报修高峰在",[21,484,485],{},"早上 9 点到 10 点","（客户上班前发现家里坏了），此时的量是日均的 5–7 倍。如果只报均值，容量规划一定会出问题。",[13,488,489],{},"吞吐量（throughput）同理：系统每秒能处理多少请求，要按峰值来定，而不是按日均。",[13,491,492,493,496,497],{},"峰值还需要注意一件事：",[21,494,495],{},"峰值不一定同时发生","。本例里「客户查进度」的峰值在早上，「工程师回填工单」的峰值在下午 5–6 点（收工前集中填），两者错开。",[21,498,499],{},"这意味着同一套服务器资源可以在一天里被两拨不同的流量复用。",[26,501,503],{"id":502},"_4-安全需求security-requirement","4 安全需求（security requirement）",[151,505,507],{"id":506},"_41-至少要写清四件事","4.1 至少要写清四件事",[13,509,510],{},"「要保证系统安全」不是需求。「要按角色控制数据可见范围」也不是 —— 还是不够具体。",[13,512,513],{},"安全需求至少要写清四件事：",[34,515,516,522,528,534],{},[37,517,518,521],{},[21,519,520],{},"认证（authentication）与授权（authorization）"," —— 谁能登录、登录后能看到和操作什么。要具体到角色与数据范围；",[37,523,524,527],{},[21,525,526],{},"加密（encryption）与脱敏"," —— 哪些字段属于敏感信息、传输和存储时怎么处理、在界面上怎么打码；",[37,529,530,533],{},[21,531,532],{},"审计日志（audit log）"," —— 哪些操作必须留痕，日志保留多久，谁能查；",[37,535,536,539],{},[21,537,538],{},"会话管理"," —— 会话有效期、异常登录的处理方式。",[13,541,542],{},"本例填出来是这样：",[61,544,545,555],{},[64,546,547],{},[67,548,549,552],{},[70,550,551],{},"项",[70,553,554],{},"本例的具体内容",[79,556,557,569,582,590],{},[67,558,559,562],{},[84,560,561],{},"认证与授权",[84,563,564,565,568],{},"客户用手机号 + 验证码；工程师与客服用工号 + 密码 + 短信二次验证；",[21,566,567],{},"工程师只能看到派给自己的工单","，客服只能看到本片区的",[67,570,571,574],{},[84,572,573],{},"加密与脱敏",[84,575,576,577,581],{},"客户手机号在界面上显示为 ",[578,579,580],"code",{},"138****5678","；地址在工程师接单前只显示到街道；数据库中对手机号与地址做加密存储",[67,583,584,587],{},[84,585,586],{},"审计日志",[84,588,589],{},"派单、改派、库存扣减、工单状态变更必须留痕（含操作人、时间、变更前后值），保留 3 年",[67,591,592,594],{},[84,593,538],{},[84,595,596],{},"客服端 30 分钟无操作自动登出；工程师 App 记住登录 7 天；同一账号异地登录需短信确认",[151,598,600],{"id":599},"_42-一个实用的追问","4.2 一个实用的追问",[13,602,603,604,607],{},"写这些内容时有个实用的问题可以问：",[21,605,606],{},"「如果这个人做了这件事，我们事后能查出来吗？」"," 如果答案是「查不出来」，这就是一条欠缺的审计需求。",[13,609,610],{},"本例里这个追问很有效：",[34,612,613,616,619],{},[37,614,615],{},"「客服能不能偷偷把一个好单派给自己熟悉的工程师？」→ 需要记「派单操作人」；",[37,617,618],{},"「仓管能不能私下扣减库存？」→ 需要记「库存变更前后值」；",[37,620,621],{},"「工程师能不能看别人片区的客户地址？」→ 需要授权控制，不只是记日志。",[13,623,624,627],{},[21,625,626],{},"注意第三条不是日志能解决的"," —— 日志只能事后追责，不能事前阻止。这也说明「审计」和「授权」是两件事，都要写。",[26,629,631],{"id":630},"_5-可靠性需求reliability-requirement","5 可靠性需求（reliability requirement）",[151,633,635],{"id":634},"_51-先定义什么叫不可用","5.1 先定义「什么叫不可用」",[13,637,638,639],{},"可靠性最容易写得含糊，因为它依赖一个关键定义：",[21,640,641],{},"什么叫「不可用」？",[34,643,644,647],{},[37,645,646],{},"是完全打不开，还是慢到用户放弃？",[37,648,649],{},"是所有人都受影响，还是只影响某一个功能？",[13,651,652],{},"本例里的定义可以写得很有分寸：",[34,654,655,661,667,677],{},[37,656,657,660],{},[21,658,659],{},"客户查进度打不开"," → 算不可用（这是最核心的体验）；",[37,662,663,666],{},[21,664,665],{},"客户查进度打开慢于 5 秒"," → 也算不可用（用户会放弃并打电话，等于没做）；",[37,668,669,672,673,676],{},[21,670,671],{},"月度报表打不开"," → ",[21,674,675],{},"不算","核心不可用（王姐可以等半小时）；",[37,678,679,682],{},[21,680,681],{},"工程师 App 打不开但网页版能用"," → 算部分不可用。",[13,684,685,686],{},"最后两条尤其重要 —— ",[21,687,688],{},"如果不先把「哪些不算不可用」写清，可用性这个指标就永远达不成。",[151,690,692],{"id":691},"_52-四项指标","5.2 四项指标",[13,694,695],{},"把这个定义写清楚之后，几项指标才有意义：",[34,697,698,704,710,720],{},[37,699,700,703],{},[21,701,702],{},"可用性（availability）目标"," —— 例如 99.9% 意味着一年允许停机约 8.8 小时，这个数字对多数系统已经相当紧；这类对服务水平的正式约定通常写在服务级别协议（SLA）里；",[37,705,706,709],{},[21,707,708],{},"故障恢复时间"," —— 出问题后多久必须恢复；",[37,711,712,715,716,719],{},[21,713,714],{},"备份与恢复"," —— 备份频率，以及",[21,717,718],{},"有没有真的演练过恢复","；",[37,721,722,725],{},[21,723,724],{},"降级（degradation）策略"," —— 部分功能故障时，是整体停掉还是让核心功能继续跑。",[13,727,728],{},"本例的降级策略可以写得很具体：",[61,730,731,741],{},[64,732,733],{},[67,734,735,738],{},[70,736,737],{},"故障",[70,739,740],{},"降级做法",[79,742,743,751,759],{},[67,744,745,748],{},[84,746,747],{},"供应商库存接口挂了",[84,749,750],{},"允许工程师先提交申请，标记「库存待确认」，不阻塞流程",[67,752,753,756],{},[84,754,755],{},"看板服务挂了",[84,757,758],{},"客服端仍可派单，看板显示「数据延迟」提示",[67,760,761,764],{},[84,762,763],{},"短信服务挂了",[84,765,766],{},"通知改走 App 内消息，并记录待补发",[13,768,769,770],{},"「降级」这一条常被忽略，但对用户体验影响很大：",[21,771,772],{},"报表打不开和派不了单，严重程度完全不同。",[13,774,775,776,779],{},"注意第一条降级的巧妙之处：",[21,777,778],{},"它把「外部依赖不可用」变成了「内部流程继续」","。这是本例里最值得写的一条 NFR —— 因为供应商接口的可用性你控制不了。",[26,781,783],{"id":782},"_6-一条合格的非功能需求长什么样","6 一条合格的非功能需求长什么样",[151,785,787],{"id":786},"_61-指标-条件-阈值","6.1 指标 + 条件 + 阈值",[13,789,790,791],{},"判断标准很简单：",[21,792,793],{},"能不能直接拿去测？",[61,795,796,806],{},[64,797,798],{},[67,799,800,803],{},[70,801,802],{},"不合格",[70,804,805],{},"合格（本例的版本）",[79,807,808,816,824,832,840],{},[67,809,810,813],{},[84,811,812],{},"系统要快",[84,814,815],{},"早 9:00–10:00 报修高峰，客户查工单进度的响应时间（response time）95 分位不超过 2 秒",[67,817,818,821],{},[84,819,820],{},"支持高并发",[84,822,823],{},"早高峰 300 客户同时在线时，派单操作成功率不低于 99.5%",[67,825,826,829],{},[84,827,828],{},"数据要安全",[84,830,831],{},"客户手机号在界面仅显示后四位，数据库中以加密形式存储",[67,833,834,837],{},[84,835,836],{},"系统要稳定",[84,838,839],{},"月度可用性不低于 99.5%，故障恢复时间不超过 30 分钟",[67,841,842,845],{},[84,843,844],{},"外部接口要可靠",[84,846,847],{},"供应商库存接口超时 3 秒即降级为「待确认」，不阻塞工程师提交",[13,849,850,851,854],{},"合格的写法包含三样东西：",[21,852,853],{},"指标 + 条件 + 阈值","。缺任何一样，都没法验证。",[13,856,857,858,861],{},"最后一行值得单独说：",[21,859,860],{},"它把「外部依赖」写进了自己的需求","。很多人只写自己的系统要多快，却忘了系统里有一半的延迟来自别人的接口。",[151,863,865],{"id":864},"_62-容易忘掉的一类","6.2 容易忘掉的一类",[13,867,868,869,872,873,876],{},"顺带说一句，非功能需求里还有一类容易被忘掉的：",[21,870,871],{},"可维护性（maintainability）"," 与 ",[21,874,875],{},"可用性（usability）"," 层面的要求 —— 例如「新成员能在一周内跑通本地环境」这类看似软性的目标。它们也是需求，只是更难测。",[26,878,880],{"id":879},"_7-常见的四个错误","7 常见的四个错误",[34,882,883,889,895,901],{},[37,884,885,888],{},[21,886,887],{},"对所有人提同样的指标。"," 查进度可以放宽到 2 秒，派单不行 —— 应该按操作类型分别定；",[37,890,891,894],{},[21,892,893],{},"只有均值没有峰值。"," 见上面第 3 节；",[37,896,897,900],{},[21,898,899],{},"只写目标不写代价。"," 99.99% 的可用性比 99.9% 贵得多。需求里最好说明「这个目标值不值得」；",[37,902,903,906],{},[21,904,905],{},"把技术方案当需求写。"," 「要用 Redis 缓存」是实现方案，不是需求。需求只说要多快、多少量。",[13,908,909],{},"本例里第一条的具体表现：如果把「查进度」和「派单」都定成「1 秒内」，那查进度那条就是浪费 —— 它一天 3600 次、每次只是读一条记录，2 秒完全够用；而为了让它 1 秒，可能要加一层缓存，多出来的复杂度换不到任何用户价值。",[26,911,912],{"id":912},"本节自测",[914,915,916,919,922,925,928,931,934,937],"ol",{},[37,917,918],{},"为什么非功能缺陷往往到上线后才暴露？这对需求阶段意味着什么？",[37,920,921],{},"三张容量表里，哪一张决定了存储与归档方案？",[37,923,924],{},"为什么必须同时给出均值和峰值？本例的峰值出现在什么时候？",[37,926,927],{},"「系统要稳定」要补上什么，才能变成一条合格的需求？",[37,929,930],{},"为什么「用 Redis 缓存」不能写成需求？",[37,932,933],{},"本例中「客户查进度的量是派单的 9 倍」，这个观察对设计有什么影响？",[37,935,936],{},"为什么必须先写清「哪些情况不算不可用」？",[37,938,939],{},"本例把「供应商接口挂了」写成降级策略，为什么这条特别值得写？",[151,941,942],{"id":942},"参考答案",[914,944,945,952,958,964,970,977,980,986],{},[37,946,947,948,951],{},"因为",[21,949,950],{},"非功能缺陷只在真实压力下才暴露","（低负载时一切正常）。所以它必须在需求阶段就量化，否则上线后改动代价最高（§1）。",[37,953,954,957],{},[21,955,956],{},"数据量表","。它决定存储、索引与归档方案，而不是接口响应（§2.3）。",[37,959,947,960,963],{},[21,961,962],{},"峰值和均值常差十倍以上","，只报均值容量规划一定出问题。本例峰值在早上 9–10 点（客户上班前发现家里坏了），是日均的 5–7 倍（§3）。",[37,965,966,967,969],{},"要补上",[21,968,853],{},"三样，例如「月度可用性不低于 99.5%，故障恢复时间不超过 30 分钟」（§6.1）。",[37,971,972,973,976],{},"因为它是",[21,974,975],{},"实现方案","，不是需求。需求只说「要多快、多少量」；一旦写成 Redis，就提前锁死了技术选择（§7）。",[37,978,979],{},"说明两者不该共用同一套设计 —— 查询量是派单的 9 倍，若走同一条重查询链路会把派单拖慢。值得为查询单独做缓存或读库分离（§2.2）。",[37,981,947,982,985],{},[21,983,984],{},"如果不先写清哪些不算不可用，可用性指标永远达不成","。本例：月报打不开不算核心不可用，工程师 App 挂了但网页版能用只算部分不可用（§5.1）。",[37,987,947,988,991],{},[21,989,990],{},"供应商接口的可用性你控制不了","。这条降级把「外部依赖不可用」转化成「内部流程继续」（允许先提交、标记待确认），是本例最值得写的一条 NFR（§5.2）。",[26,993,994],{"id":994},"术语表",[61,996,997,1010],{},[64,998,999],{},[67,1000,1001,1004,1007],{},[70,1002,1003],{},"术语",[70,1005,1006],{},"中文",[70,1008,1009],{},"一句话解释",[79,1011,1012,1022,1033,1044,1055,1066,1077,1088,1098,1109,1120,1131,1142,1153,1164,1174,1185,1196,1207,1218],{},[67,1013,1014,1017,1019],{},[84,1015,1016],{},"non-functional requirement（NFR）",[84,1018,77],{},[84,1020,1021],{},"描述系统做得多好的需求",[67,1023,1024,1027,1030],{},[84,1025,1026],{},"performance requirement",[84,1028,1029],{},"性能需求",[84,1031,1032],{},"对响应时间、吞吐量等的要求",[67,1034,1035,1038,1041],{},[84,1036,1037],{},"response time",[84,1039,1040],{},"响应时间",[84,1042,1043],{},"从发出请求到得到响应的时间",[67,1045,1046,1049,1052],{},[84,1047,1048],{},"throughput",[84,1050,1051],{},"吞吐量",[84,1053,1054],{},"单位时间内能处理的请求数量",[67,1056,1057,1060,1063],{},[84,1058,1059],{},"concurrent user",[84,1061,1062],{},"同时在线用户数",[84,1064,1065],{},"同一时刻活跃的用户数量",[67,1067,1068,1071,1074],{},[84,1069,1070],{},"user volume table",[84,1072,1073],{},"用户量表",[84,1075,1076],{},"按类型统计用户规模的表",[67,1078,1079,1082,1085],{},[84,1080,1081],{},"business transaction volume table",[84,1083,1084],{},"业务交易量表",[84,1086,1087],{},"按交易类型统计发生次数的表",[67,1089,1090,1093,1095],{},[84,1091,1092],{},"data volume table",[84,1094,956],{},[84,1096,1097],{},"按数据对象统计增长量的表",[67,1099,1100,1103,1106],{},[84,1101,1102],{},"peak load",[84,1104,1105],{},"峰值负载",[84,1107,1108],{},"最繁忙时段承受的负载",[67,1110,1111,1114,1117],{},[84,1112,1113],{},"scalability",[84,1115,1116],{},"可扩展性",[84,1118,1119],{},"规模增长时系统仍能保持表现的能力",[67,1121,1122,1125,1128],{},[84,1123,1124],{},"security requirement",[84,1126,1127],{},"安全需求",[84,1129,1130],{},"对认证、授权、加密、审计等的要求",[67,1132,1133,1136,1139],{},[84,1134,1135],{},"authentication",[84,1137,1138],{},"认证",[84,1140,1141],{},"确认「你是谁」",[67,1143,1144,1147,1150],{},[84,1145,1146],{},"authorization",[84,1148,1149],{},"授权",[84,1151,1152],{},"确认「你能做什么」",[67,1154,1155,1158,1161],{},[84,1156,1157],{},"encryption",[84,1159,1160],{},"加密",[84,1162,1163],{},"把敏感数据转换成人读不懂的形式",[67,1165,1166,1169,1171],{},[84,1167,1168],{},"audit log",[84,1170,586],{},[84,1172,1173],{},"记录关键操作的日志，用于事后追溯",[67,1175,1176,1179,1182],{},[84,1177,1178],{},"reliability requirement",[84,1180,1181],{},"可靠性需求",[84,1183,1184],{},"对可用性与故障恢复的要求",[67,1186,1187,1190,1193],{},[84,1188,1189],{},"availability",[84,1191,1192],{},"可用性",[84,1194,1195],{},"系统处于可服务状态的时间比例",[67,1197,1198,1201,1204],{},[84,1199,1200],{},"SLA",[84,1202,1203],{},"服务级别协议",[84,1205,1206],{},"对服务水平的正式约定",[67,1208,1209,1212,1215],{},[84,1210,1211],{},"degradation",[84,1213,1214],{},"降级",[84,1216,1217],{},"部分能力失效时保留核心功能运行",[67,1219,1220,1223,1226],{},[84,1221,1222],{},"maintainability",[84,1224,1225],{},"可维护性",[84,1227,1228],{},"系统被理解和修改的难易程度",{"title":1230,"searchDepth":1231,"depth":1231,"links":1232},"",3,[1233,1235,1236,1242,1243,1247,1251,1255,1256,1259],{"id":28,"depth":1234,"text":29},2,{"id":58,"depth":1234,"text":59},{"id":142,"depth":1234,"text":143,"children":1237},[1238,1239,1240,1241],{"id":153,"depth":1231,"text":154},{"id":238,"depth":1231,"text":239},{"id":355,"depth":1231,"text":356},{"id":438,"depth":1231,"text":439},{"id":468,"depth":1234,"text":469},{"id":502,"depth":1234,"text":503,"children":1244},[1245,1246],{"id":506,"depth":1231,"text":507},{"id":599,"depth":1231,"text":600},{"id":630,"depth":1234,"text":631,"children":1248},[1249,1250],{"id":634,"depth":1231,"text":635},{"id":691,"depth":1231,"text":692},{"id":782,"depth":1234,"text":783,"children":1252},[1253,1254],{"id":786,"depth":1231,"text":787},{"id":864,"depth":1231,"text":865},{"id":879,"depth":1234,"text":880},{"id":912,"depth":1234,"text":912,"children":1257},[1258],{"id":942,"depth":1231,"text":942},{"id":994,"depth":1234,"text":994},"学习",null,"2026-11-06","为什么「系统要快」不是一条需求：非功能需求怎么量化，决定性能的用户量、交易量、数据量三张表怎么估，安全需求要写清什么，以及可靠性的「不可用」该怎么定义。","md",false,{},true,"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-15",{"title":5,"description":1263},"软件分析与设计笔记",15,"posts\u002FswDesign\u002Fsw-design-notes-15",[1274,77,1275,1276],"需求分析","系统性能","学习笔记","wTRP7kh50z_SVfmbMDi6GpMshRpz_Z8zPTxuOxQ3Lwo",[1279,1285,1291,1297,1303,1309,1315,1321,1327,1333,1339,1345,1351,1357,1358,1364,1370,1376,1382,1388,1394,1400,1406,1412,1418,1424,1429,1434,1440,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1496,1500,1506,1510,1514,1518,1522,1526,1530,1534,1539,1543,1547,1552,1557,1563,1567,1572,1576],{"path":1280,"title":1281,"description":1282,"date":1283,"series":1270,"seriesOrder":1284},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-28","软件分析与设计笔记 28：draw.io 作图手册：五张图的符号位置、落笔顺序与自检","不模拟软件界面，只讲清三件事：每个 UML 符号在 draw.io 里搜什么词、一张图该按什么顺序落笔、画完拿什么标准自查。覆盖用例图、活动图、顺序图、类图、界面草图五种图纸，末尾附「最容易画反的十二笔」总检表。","2026-11-19",28,{"path":1286,"title":1287,"description":1288,"date":1289,"series":1270,"seriesOrder":1290},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-27","软件分析与设计笔记 27：Paper 1 应试：从读案例到交卷的一次完整演算","拿一份完整的案例，从头到尾走一遍：怎么读案例列角色、怎么在四个小问之间分配时间、每一张图从哪一句话推出来、两张表怎么填、交卷前拿什么清单自查。附 C25 真题与样卷的题型分值对照。","2026-11-18",27,{"path":1292,"title":1293,"description":1294,"date":1295,"series":1270,"seriesOrder":1296},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-26","软件分析与设计笔记 26：总结：把整条链路串起来","系列收尾：从需求到代码的完整链路回顾、每一环的产出与验收方式、六条贯穿全系列的原则，以及一份可以直接拿去做项目自查的清单。","2026-11-17",26,{"path":1298,"title":1299,"description":1300,"date":1301,"series":1270,"seriesOrder":1302},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-25","软件分析与设计笔记 25：代码重构：坏味道与手法","重构不改变外部行为、只改善内部结构：四种常见坏味道与对应手法、为什么动手之前必须先有测试、什么时候该重构，以及重构和前面那些设计模型是什么关系。","2026-11-16",25,{"path":1304,"title":1305,"description":1306,"date":1307,"series":1270,"seriesOrder":1308},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-24","软件分析与设计笔记 24：设计原则：内聚、耦合与多态","好设计怎么衡量：内聚与耦合分别在说什么、一次从「差设计」到「多态重设计」的完整对照、抽象类与接口的选择依据，以及复用为什么会从优势变成风险。","2026-11-15",24,{"path":1310,"title":1311,"description":1312,"date":1313,"series":1270,"seriesOrder":1314},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-23","软件分析与设计笔记 23：设计建模：从对象模型到能实现的方案","分析模型能用但还不能直接开工：对象模型怎么映射到关系模型、继承映射的三种方案怎么选、数据访问层与 Data Broker 解决什么问题，以及三层架构与 MVC 的分工。","2026-11-14",23,{"path":1316,"title":1317,"description":1318,"date":1319,"series":1270,"seriesOrder":1320},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-22","软件分析与设计笔记 22：分析建模：边界、实体与控制对象","不经过分析直接写代码会踩什么坑、三种分析对象各管一段、怎么用顺序图完成一次用例实现，以及从顺序图导出类的属性、操作与关系的方法。","2026-11-13",22,{"path":1322,"title":1323,"description":1324,"date":1325,"series":1270,"seriesOrder":1326},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-21","软件分析与设计笔记 21：UML：类图与顺序图","为什么需要一种共同的画法：类符号三格怎么画、五种关系的符号与设计含义、每种关系落到 Java 是什么写法，顺序图的三要素怎么摆；以及这三种最容易找不到的符号在 draw.io 里各搜什么词。","2026-11-12",21,{"path":1328,"title":1329,"description":1330,"date":1331,"series":1270,"seriesOrder":1332},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-20","软件分析与设计笔记 20：面向对象概念：对象、关系与多态","面向对象不是「用某个语言写代码」：对象与类的区别、封装真正在保护什么、五种关系（依赖、关联、聚合、组合、继承）各自何时用，以及多态为什么能减少条件判断。","2026-11-11",20,{"path":1334,"title":1335,"description":1336,"date":1337,"series":1270,"seriesOrder":1338},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-19","软件分析与设计笔记 19：规范化与逻辑数据模型","一次改地址引发的数据不一致，讲清规范化的真正动机；UNF 到 3NF 每一步在解决什么问题，派生字段为什么不能存，优化为什么和规范化方向相反，以及逻辑数据模型在 3NF 之上补了什么。","2026-11-10",19,{"path":1340,"title":1341,"description":1342,"date":1343,"series":1270,"seriesOrder":1344},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-18","软件分析与设计笔记 18：数据库分析：实体、关系与数据字典","为什么不能拿到需求就动手建表：实体与关系怎么判定、基数为什么必须由业务方确认、数据命名要遵守什么规则，以及数据字典四列里最容易被空着的那一列。","2026-11-09",18,{"path":1346,"title":1347,"description":1348,"date":1349,"series":1270,"seriesOrder":1350},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-17","软件分析与设计笔记 17：用生成式 AI 做设计与开发：能用的场景与要防的坑","生成式 AI 在工作流里真正站得住的三个场景 —— 造示例数据、解释陌生代码、起草初稿；它为什么会复现社会偏见、为什么会编得像真的，以及哪些内容绝不能直接采用。","2026-11-08",17,{"path":1352,"title":1353,"description":1354,"date":1355,"series":1270,"seriesOrder":1356},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-16","软件分析与设计笔记 16：从 persona 到 URS：一份交付物的完整骨架","把前面十几篇串成一份能交出去的东西：用户需求规格说明书的九个部分、每一章来自哪个环节、由谁确认，以及面向决策者的提案该讲清哪三件事。","2026-11-07",16,{"path":1268,"title":5,"description":1263,"date":1262,"series":1270,"seriesOrder":1271},{"path":1359,"title":1360,"description":1361,"date":1362,"series":1270,"seriesOrder":1363},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-14","软件分析与设计笔记 14：软件测试：层级、方法与等价类划分","「我们测过了」这句话问题在哪：为什么静态评审和动态测试缺一不可，五个测试层级各自验证什么，白盒与黑盒的差别，以及用等价类划分和边界值把无限输入变成有限用例的方法。","2026-11-05",14,{"path":1365,"title":1366,"description":1367,"date":1368,"series":1270,"seriesOrder":1369},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-13","软件分析与设计笔记 13：需求获取：五种调查方法与一场访谈","需求从哪里来：五种事实调查方法各自适合回答什么、代价是什么，访谈从准备到记录的全过程，问卷设计里最容易犯的错，以及访谈记录必须写下来的那几项信息。","2026-11-04",13,{"path":1371,"title":1372,"description":1373,"date":1374,"series":1270,"seriesOrder":1375},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-12","软件分析与设计笔记 12：前端设计：把流程变成屏幕","界面设计不是「画得好看」：从活动图走到屏幕的三步，CRUD 任务流怎么当检查表，界面必须回答的三个问题，信息架构与五种导航类型，视觉一致性与留白，以及移动端与 Web 端的差别。","2026-11-03",12,{"path":1377,"title":1378,"description":1379,"date":1380,"series":1270,"seriesOrder":1381},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-11","软件分析与设计笔记 11：Agentic AI 与业务流程自动化","AI agent 到底是什么：五项能力与四个核心组件，什么场景该用定时任务、什么该用程序、什么才值得用 agent，两种实现路径的差别，必须提前防住的四类失败模式，以及设计方法从提示词到编排的演进。","2026-11-02",11,{"path":1383,"title":1384,"description":1385,"date":1386,"series":1270,"seriesOrder":1387},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-10","软件分析与设计笔记 10：精炼用例模型：include、extend 与泛化","三种精炼用例关系的判断标准：include 什么时候用、它和 extend 的区别到底在哪、参与者泛化与用例泛化各解决什么问题，以及精炼到什么程度就该停手。","2026-11-01",10,{"path":1389,"title":1390,"description":1391,"date":1392,"series":1270,"seriesOrder":1393},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-09","软件分析与设计笔记 09：功能需求（二）：从流程到业务实体","活动图画完之后，怎么从流程里筛出真正的业务实体：三条判断标准、哪些名词其实不该建实体、属性从哪里来，以及领域模型和后面的数据模型分别负责什么。","2026-10-31",9,{"path":1395,"title":1396,"description":1397,"date":1398,"series":1270,"seriesOrder":1399},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-08","软件分析与设计笔记 08：功能需求（一）：用例模型与活动图","从用户故事到用例的翻译过程：什么才算「好」的参与者，系统边界怎么划，用例描述必须写清哪四件事，活动图怎么把分支、并行与泳道画清楚，以及这两个图在 draw.io 里各用哪个形状、最容易画错哪一笔。","2026-10-30",8,{"path":1401,"title":1402,"description":1403,"date":1404,"series":1270,"seriesOrder":1405},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-07","软件分析与设计笔记 07：用户故事：把需求写成可验收的一句话","用户故事的三段结构，怎么从用户画像和数据地图里把它提取出来，一条故事多大算合适、时序为什么也是需求的一部分，以及验收标准怎么写才算真的可验收。","2026-10-29",7,{"path":1407,"title":1408,"description":1409,"date":1410,"series":1270,"seriesOrder":1411},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-06","软件分析与设计笔记 06：范围界定（数据侧）：用数据校验你的判断","访谈结论和数字对不上时该怎么办：分析的四个层次分别在回答什么问题、为什么不能跳级、数据准备与搜集怎么做成一张应用地图，以及数据最容易在哪几个地方骗你。","2026-10-28",6,{"path":1413,"title":1414,"description":1415,"date":1416,"series":1270,"seriesOrder":1417},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-05","软件分析与设计笔记 05：范围界定（用户侧）：用户画像与客户旅程图","为什么「所有用户」是一个陷阱，项目边界该怎么划，用户画像要写哪五个要素、最容易写成什么废纸，客户旅程图怎么把阶段、想法和情绪画在同一张纸上，以及怎么从这两样东西一步步推到可验证的需求。","2026-10-27",5,{"path":1419,"title":1420,"description":1421,"date":1422,"series":1270,"seriesOrder":1423},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-04","软件分析与设计笔记 04：接手陌生案例的第一步：三问与一张表","拿到一个完全陌生的业务案例，怎么从零开始不跑偏：只问 Who、What、Why 三个问题，把「问题—事实—假设—理由」记成一张四列表，说清为什么假设必须写明理由，以及带着问题进访谈为什么比空手去有效得多。","2026-10-26",4,{"path":1425,"title":1426,"description":1427,"date":1428,"series":1270,"seriesOrder":1231},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-03","软件分析与设计笔记 03：Agile 与 Scrum：迭代、角色与产出物","从「三周做完交付，客户说这不是我要的」讲起，说清瀑布式与迭代式的根本差别，Scrum 的三个角色和三种产出物，一个 sprint 里四次固定活动各自在解决什么问题，以及敏捷里最常见的几个误解。","2026-10-25",{"path":1430,"title":1431,"description":1432,"date":1433,"series":1270,"seriesOrder":1234},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-02","软件分析与设计笔记 02：设计思维、用户驱动与数据驱动","从「客服要一个能一次看完所有排期的界面」这个翻车案例讲起，说清设计思维到底是什么、用户驱动与数据驱动各自能看见什么又看不见什么、为什么真正的落点是把两者合起来的 data-informed design，以及访谈中怎么问出有用的信息。","2026-10-24",{"path":1435,"title":1436,"description":1437,"date":1438,"series":1270,"seriesOrder":1439},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-01","软件分析与设计笔记 01：课程地图与从需求到设计的主干","这一篇不写具体方法，先把整条链路铺开：软件分析与设计到底要解决什么问题，从需求到设计分成哪两段，中间有哪十几个环节，一份完整的交付物里应该有什么，以及后面 27 篇笔记怎么排、新人该按什么顺序读。","2026-10-23",1,{"path":1441,"title":1442,"description":1443,"date":1444,"series":1445,"seriesOrder":1439},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-01","Spring 学习笔记 01：IoC、依赖注入与第一个 Spring Boot 应用","从「手写 new 出来的三层结构」的痛点讲起，说清 IoC 容器、Bean 与依赖注入是怎么回事，再用 Maven 与 Spring Initializr 跑起第一个能返回 JSON 的应用。","2026-10-15","Spring 学习笔记",{"path":1447,"title":1448,"description":1449,"date":1444,"series":1445,"seriesOrder":1234},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-02","Spring 学习笔记 02：Spring Data JPA 基础——实体映射与 Repository","用 ORM 把类映射到表：@Entity、@Id、@GeneratedValue 怎么用，CrudRepository 三层接口怎么选，H2 与 MySQL 怎么配，以及 ddl-auto 到底该写哪个值。",{"path":1451,"title":1452,"description":1453,"date":1444,"series":1445,"seriesOrder":1231},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-03","Spring 学习笔记 03：JPA 查询——派生方法、JPQL 与分页排序","Repository 自带的方法只够按主键查，这篇讲三种自己造查询的方式：方法名派生、@Query 写 JPQL、原生 SQL，以及 Pageable 分页排序和投影返回。",{"path":1455,"title":1456,"description":1457,"date":1444,"series":1445,"seriesOrder":1423},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-04","Spring 学习笔记 04：JPA 关联映射与仓储测试","一对多、多对多怎么映射，谁负责维护外键，FetchType 与 CascadeType 该怎么选，顺带用 @DataJpaTest 与 AssertJ 把仓储层测起来。",{"path":1459,"title":1460,"description":1461,"date":1444,"series":1445,"seriesOrder":1417},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-05","Spring 学习笔记 05：Spring MVC 与 Thymeleaf 入门","一次页面请求在 Spring MVC 里走了哪几步，@Controller 怎么把数据交给模板，@PathVariable 与 @RequestParam 怎么取参数，以及控制器为什么必须是无状态的。",{"path":1463,"title":1464,"description":1465,"date":1444,"series":1445,"seriesOrder":1411},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-06","Spring 学习笔记 06：表单绑定与服务端校验","把表单字段绑到对象上，用 Bean Validation 注解做服务端校验，把错误信息显示回用户刚填的那一页，再补上自定义校验注解与全局异常处理。",{"path":1467,"title":1468,"description":1469,"date":1444,"series":1445,"seriesOrder":1405},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-07","Spring 学习笔记 07：Thymeleaf 片段复用与国际化","用 th:fragment 与 th:insert\u002Fth:replace 把导航栏、页脚抽成片段，页面套用统一布局，再用 messages.properties 与 LocaleResolver 做中英文切换。",{"path":1471,"title":1472,"description":1473,"date":1444,"series":1445,"seriesOrder":1399},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-08","Spring 学习笔记 08：HTTP Session 与会话状态管理","HTTP 无状态带来的问题，Cookie 与 Session 怎么分工，Spring 里读写会话的几种方式，以及会话固定、超时、多实例共享这些必须想清楚的事。",{"path":1475,"title":1476,"description":1477,"date":1444,"series":1445,"seriesOrder":1393},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-09","Spring 学习笔记 09：拦截器 HandlerInterceptor","登录检查、权限判断、请求耗时统计这类横切逻辑该放哪：HandlerInterceptor 的三个回调各在什么时机执行，怎么注册与排除路径，以及它和过滤器的分工。",{"path":1479,"title":1480,"description":1481,"date":1444,"series":1445,"seriesOrder":1387},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-10","Spring 学习笔记 10：Service 层与事务","一组数据库操作要么全成功要么全失败，靠 @Transactional 怎么做到；传播行为、隔离级别、回滚规则怎么选，以及自调用失效、乐观锁悲观锁这些实战里的坑。",{"path":1483,"title":1484,"description":1485,"date":1444,"series":1445,"seriesOrder":1381},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-11","Spring 学习笔记 11：REST API 基础——把 Service 暴露成接口","同一套 Service 怎么同时服务页面和客户端：@RestController 的路由与方法语义、状态码怎么给、DTO 怎么定，以及 MockMvc 端到端和切片测试的两种写法与各自的坑。",{"path":1487,"title":1488,"description":1489,"date":1444,"series":1445,"seriesOrder":1375},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-12","Spring 学习笔记 12：REST 进阶——版本、更新、跨域与文档化","接口能跑通之后要处理的几件事：URL 与响应结构怎么定、版本怎么演进、更新怎么做到可安全重试、CORS 怎么配、HATEOAS 与 Spring Data REST 该不该用。",{"path":1491,"title":1492,"description":1493,"date":1494,"series":1495,"seriesOrder":1423},"\u002Fposts\u002Fjava\u002Fjava-functionalprogramming-notes","Java 函数式编程笔记：Lambda、函数式接口与 Streams","学习 Java 函数式编程时的个人笔记：Lambda 表达式的五步简写与方法引用、常见函数式接口、Stream 流水线与惰性求值，以及创建流、中间操作、终止操作与收集器的用法。示例代码均为自写，运行结果来自本地实测。","2026-10-13","Java 学习笔记",{"path":1497,"title":1498,"description":1499,"date":1494,"series":1495,"seriesOrder":1231},"\u002Fposts\u002Fjava\u002Fjava-generics-notes","Java 泛型笔记：泛型方法、有界类型与泛型类","学习 Java 泛型时的个人笔记：从重复的重载方法与多态尝试讲起，再到泛型方法与类型推断、有界泛型类型、Comparable 与 Number 边界，以及泛型类在集合中的用法。示例代码均为自写，运行结果来自本地实测。",{"path":1501,"title":1502,"description":1503,"date":1504,"series":1505,"seriesOrder":1423},"\u002Fposts\u002Fmysql\u002Fmysql-learning-04","MySQL 学习笔记 04：数据操纵（增删改）","MySQL 学习笔记第四篇：INSERT 插入（含批量插入与 INSERT ... SELECT）、UPDATE 更新、DELETE 删除，以及各自的坑。","2026-10-10","SQL 学习笔记",{"path":1507,"title":1508,"description":1509,"date":1504,"series":1505,"seriesOrder":1417},"\u002Fposts\u002Fmysql\u002Fmysql-learning-05","MySQL 学习笔记 05：DDL 概览","MySQL 学习笔记第五篇：数据定义语言概览——Schema、Table、View、Index、Constraints 这几类对象分别对应哪些 CREATE \u002F ALTER \u002F DROP 命令。",{"path":1511,"title":1512,"description":1513,"date":1504,"series":1505,"seriesOrder":1411},"\u002Fposts\u002Fmysql\u002Fmysql-learning-06","MySQL 学习笔记 06：CREATE TABLE 与数据类型","MySQL 学习笔记第六篇：CREATE TABLE 的完整语法、常用数据类型的选型建议，以及外键的两种定义方式。",{"path":1515,"title":1516,"description":1517,"date":1504,"series":1505,"seriesOrder":1405},"\u002Fposts\u002Fmysql\u002Fmysql-learning-07","MySQL 学习笔记 07：索引","MySQL 学习笔记第七篇：索引的作用与 B+ 树结构、单列与复合索引的创建、索引的代价与适用场景。",{"path":1519,"title":1520,"description":1521,"date":1504,"series":1505,"seriesOrder":1399},"\u002Fposts\u002Fmysql\u002Fmysql-learning-08","MySQL 学习笔记 08：DROP 与 ALTER","MySQL 学习笔记第八篇：DROP 删除数据库对象、ALTER 修改表结构，以及常见的坑。",{"path":1523,"title":1524,"description":1525,"date":1504,"series":1505,"seriesOrder":1393},"\u002Fposts\u002Fmysql\u002Fmysql-learning-09","MySQL 学习笔记 09：约束与数据完整性","MySQL 学习笔记第九篇：SQL 约束——NOT NULL、CHECK、PRIMARY KEY、FOREIGN KEY 等如何保证数据完整性，以及它们的对比。",{"path":1527,"title":1528,"description":1529,"date":1504,"series":1505,"seriesOrder":1387},"\u002Fposts\u002Fmysql\u002Fmysql-learning-10","MySQL 学习笔记 10：视图","MySQL 学习笔记第十篇：视图（Views）的定义与特性、和表的对比、创建与使用，以及可更新视图的限制。",{"path":1531,"title":1532,"description":1533,"date":1504,"series":1505,"seriesOrder":1381},"\u002Fposts\u002Fmysql\u002Fmysql-learning-11","MySQL 学习笔记 11：存储过程","MySQL 学习笔记第十一篇：存储过程（Stored Procedures）的概念、创建与调用、带参数的写法，以及优缺点。",{"path":1535,"title":1536,"description":1537,"date":1538,"series":1505,"seriesOrder":1439},"\u002Fposts\u002Fmysql\u002Fmysql-learning-01","MySQL 学习笔记 01：MySQL 基础知识","MySQL 学习笔记第一篇：MySQL Server 与 Workbench 的安装，数据库与 DBMS 的基本概念，关系模型、ACID 事务、常见数据类型，以及后续的学习路线。","2026-10-09",{"path":1540,"title":1541,"description":1542,"date":1538,"series":1505,"seriesOrder":1234},"\u002Fposts\u002Fmysql\u002Fmysql-learning-02","MySQL 学习笔记 02：SELECT 查询与过滤","MySQL 学习笔记第二篇：SELECT 的基本语法与逻辑执行顺序，WHERE 过滤（比较、LIKE、IN、BETWEEN、NULL）、各种 JOIN、UNION 与子查询。",{"path":1544,"title":1545,"description":1546,"date":1538,"series":1505,"seriesOrder":1231},"\u002Fposts\u002Fmysql\u002Fmysql-learning-03","MySQL 学习笔记 03：聚合、分组与输出控制","MySQL 学习笔记第三篇：COUNT\u002FSUM\u002FAVG 等聚合函数、GROUP BY 分组、HAVING 过滤、ORDER BY 与 LIMIT，以及一条 SELECT 的完整逻辑执行顺序。",{"path":1548,"title":1549,"description":1550,"date":1551,"series":1495,"seriesOrder":1234},"\u002Fposts\u002Fjava\u002Fjava-oop-notes","Java 面向对象笔记：类、继承、多态与异常","学习 Java 面向对象编程时的个人笔记：类与对象、封装与访问修饰符、继承与多态、集合、抽象类与接口、异常处理。示例代码均为自写，运行结果来自本地实测。","2026-10-06",{"path":1553,"title":1554,"description":1555,"date":1556,"series":1495,"seriesOrder":1439},"\u002Fposts\u002Fjava\u002Fjava-basics-notes","Java 基础语法笔记：从环境安装到方法与数组","学习 Java 基础语法时的个人笔记：JDK 安装、输入输出、变量与运算符、条件与循环、字符串、数组与方法。示例代码均为自写，运行结果来自本地实测。","2026-10-05",{"path":1558,"title":1559,"description":1560,"date":1561,"series":1562,"seriesOrder":1439},"\u002Fposts\u002Fgit\u002Fgit-install-and-basics","Git 安装与基本使用","从装好 Git 到跑通日常提交流程，把最常用的几条命令和它们背后的三个区域讲清楚。","2026-10-04","Git 入门",{"path":1564,"title":1565,"description":1566,"date":1561,"series":1562,"seriesOrder":1234},"\u002Fposts\u002Fgit\u002Flocal-remote-repository","本地远程仓库的部署","用自己的机器当 Git 服务器：建一个裸仓库、走 SSH 连上去，把本地提交推上去。",{"path":1568,"title":1569,"description":1570,"date":1561,"series":1571,"seriesOrder":1439},"\u002Fposts\u002Fguide\u002Fguide-file-layout","文件都放在哪","文章、图片、封面分别放在仓库的什么位置，哪些目录可以放手改、哪些碰了会出问题。","博客使用指南",{"path":1573,"title":1574,"description":1575,"date":1561,"series":1571,"seriesOrder":1234},"\u002Fposts\u002Fguide\u002Fguide-frontmatter","frontmatter 每个字段是什么意思","文章开头那段被横线包住的字段，逐个说明作用、默认行为和写错的后果。",{"path":1577,"title":1578,"description":1579,"date":1561,"series":1571,"seriesOrder":1231},"\u002Fposts\u002Fguide\u002Fguide-markdown","正文怎么写 —— Markdown 与排版效果","标题、链接、图片、代码、表格分别怎么写，以及本站对它们做了哪些自定义处理。",1793268185284]