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