EMall实践DDD模拟电商系统总结
目录
一、事件风暴
二、系统用例
三、领域上下文
四、架构设计
(一)六边形架构
(二)系统分层
五、系统实现
(一)项目结构
(二)提交订单功能实现
(三)领域层实现
聚合
聚合根、实体、值对象
(四)Repository层实现
CQRS模式
缓存实现
Unit Of Work模式
数据并发更新控制
(五)领域事件实现
六、总结
干货分享,感谢您的阅读!
在这个信息化爆炸的时代,软件开发就像是烹饪一顿大餐,尤其是对于复杂的电商系统E-Mall而言。你得准备好各种“食材”,从用户需求、系统架构到领域模型,少了哪一样,整个“菜单”可就难以下咽了!而我们的厨房——事件风暴(Event Storming),就是一个绝妙的集思广益的环节,人人都是大厨,尽情挥舞着“锅铲”,共同烹制出一道色香味俱全的系统设计大餐。
但别担心,咱们不是要把你弄得一头雾水。相反,我们会用一种轻松幽默的方式,带你走进系统分析的世界,像讲故事一样剖析复杂的概念。想象一下,你正在与小伙伴们一起玩一场解谜游戏,破解那些神秘的业务需求,发现隐藏的领域上下文,最终打造出一个能让用户眼前一亮的电商平台。
准备好了吗?让我们一起在这场系统设计的盛宴中,开启“食材”之旅,探索如何用合理的架构和设计理念,将E-Mall打造成“软件界的美食大师”!针对项目源码roc-emall进行的一些总结。
一、事件风暴
事件风暴(Event Storming)是一种系统分析方法,由 Alberto Brandolini 开发,旨在帮助团队理解和识别系统中的事件、业务功能和边界。它通常与领域驱动设计(DDD)概念结合使用,以加速系统设计和开发的过程。 详细的解释可以参考它的官方网站: Event Storming。
事件风暴的核心思想是通过协作的方式,将参与者集合在一起,共同探讨和记录系统中发生的事件。以下是事件风暴的一些关键要点:
-
事件驱动:事件风暴强调事件作为系统的关键组成部分。事件是用户操作或系统状态更改的结果,这些事件可以帮助理解系统中的业务流程。
-
合作工作坊:事件风暴通常作为一个工作坊进行,邀请各种利益相关者参与,包括业务分析师、开发人员、设计师等。这有助于促进跨职能团队的合作和理解。
-
大白纸:事件风暴使用大型纸张或墙壁来记录事件和相关信息。参与者可以使用便利贴、标记笔等工具来记录事件,定义业务流程,绘制关系图等。
-
时间线:事件风暴通常将事件按照时间线的方式排列,以帮助理清事件发生的顺序和逻辑。
-
聚焦领域:事件风暴有助于识别领域中的限界上下文(bounded context),这是DDD中的一个重要概念,用于定义业务功能的边界。
-
快速迭代:事件风暴是一个迭代过程,可以多次进行,以不断完善对系统的理解,发现潜在的业务问题和机会。
事件风暴的目标是促进对系统的共享理解,减少误解,发现潜在问题,以及为设计和开发提供清晰的指导。它是一种轻量级、可视化的方法,有助于团队在项目早期阶段快速建立共识,加速开发过程,提高项目成功的机会。
所谓“事件”,即系统中一系列的行为(用户操作)导致系统状态更改的结果。例如,用户“提交订单”这一行为导致系统生成了新订单,发生了“订单已提交”事件;仓库发货员将包果交给快递员后,在系统“填写了快递单号”后,导致系统状态发生更改,触发了“已发货”事件。
通过分析系统中发生的“事件”,能够挖掘和识别出系统的业务功能,梳理出业务边界。下图展示了E-Mall系统的事件风暴
二、系统用例
系统用例是用户与系统交互的一种表示形式,它们有助于识别和记录系统的功能需求,并可用于用户需求分析、系统设计和软件开发的各个阶段。以下是有关系统用例的一些关键要点:
-
用户需求分析: 通过系统用例,分析人员可以捕捉用户与系统之间的交互,以了解用户期望系统执行的各种操作。这有助于确保系统开发满足用户需求。
-
功能识别: 用例图用于识别系统的各种功能或操作。每个用例代表一个特定的功能或行为,而用例之间的关系描述了它们之间的依赖性和交互。
-
可视化: 用例图提供了一种可视化方式,以便项目团队、利益相关者和开发人员更容易理解系统功能和交互。
-
系统边界: 用例图通常包括一个系统边界,用于明确界定系统与外部实体之间的交互,帮助确定哪些操作属于系统的范围。
-
用例描述: 每个用例通常附带用例描述,其中包括用例的名称、目标、前提条件、主要流程和可能的替代流程。这些描述提供了对用例的详细说明。
-
角色: 用例图还包括与系统交互的各种角色,这些角色代表用户、外部系统或其他实体。
-
交互关系: 用例图展示了各个用例之间的关系,如包含关系、扩展关系和依赖关系。这有助于理解用例之间的交互方式。
-
迭代和演化: 用例图是一个灵活的工具,可以在项目的不同阶段进行更新和演化,以反映新的需求或发现的变化。
总之,系统用例图是一种强大的工具,用于捕捉、可视化和分析系统的功能需求,有助于确保开发团队理解用户期望的系统行为,从而成功交付符合需求的软件系统。下图展示了E-Mall系统的用例:
三、领域上下文
根据事件风暴推断,系统中应该包含的界限上下文有:Order、SKU、Price、Payment等。
对系统进行Context划分:
-
Order Context(订单上下文): 这是处理与订单相关的所有功能的上下文,包括提交订单、取消订单和查询订单等操作。它在业务中负责订单的生命周期管理。
-
SKU Context(SKU上下文): 这个上下文主要涉及商品(Stock Keeping Unit)的管理,包括库存管理、商品数量校验以及订单的商品处理。此外,SKU上下文还涉及订单的打包和发货等操作,以确保订单的正确处理。
-
Price Context(价格上下文): 价格上下文负责管理商品的价格,计算订单金额以及维护价格计算策略。它为订单上下文提供了订单金额计算所需的功能。
-
Payment Context(支付上下文): 这个上下文主要关注支付功能,包括维护交易记录等。它确保订单支付的安全性和可追踪性。
四、架构设计
(一)六边形架构
六边形架构是一种用于构建可扩展和灵活的应用程序的架构风格,强调了分离关注点和对外部系统和客户的透明性。以下是一些关键要点:
-
六边形的对称性: 在六边形架构中,系统被视为一个多边形,其边界上有各种端口(Port),而系统的核心是领域层。这个多边形的对称性意味着客户和外部系统可以以一种对等的方式与系统交互,而系统核心不受特定的客户或外部技术的依赖。
-
输入端口: 输入端口用于接受外部客户系统的请求或输入,并将其转化为内部可理解的请求。这可以是系统提供的服务接口,用于接受来自外部的命令或查询。
-
输出端口: 输出端口用于与外部系统进行通信,如数据库、消息队列、远程服务等。它负责将系统内部的状态或数据发送到外部系统或进行持久化。
-
应用层: 应用层是系统的服务层,定义了系统可以执行的工作。它协调领域对象和领域服务,处理业务逻辑,并通过输入端口接受请求并使用输出端口与外部系统通信。应用层通常非常薄,不包含业务逻辑,而是将请求委托给领域层处理。
-
领域层: 领域层包含系统的核心业务逻辑,它负责表示业务概念、规则和状态。领域层的模型是应用程序的核心,通常包括实体、值对象、聚合根等领域对象。
-
适配器: 适配器在输入和输出端口之间进行数据转换和交互。输入适配器将来自客户的请求转化为系统可理解的形式,输出适配器将系统的响应转化为外部系统或客户可理解的形式。这使得系统能够与各种客户和外部系统进行无缝的交互。
六边形架构的优点包括良好的可扩展性、可维护性和适应性,因为它使不同部分之间的关注点清晰分离。它也使系统更容易进行单元测试,因为领域逻辑可以在不涉及外部系统的情况下进行测试。这种架构风格对于构建复杂应用程序和微服务架构非常有用。
(二)系统分层
领域驱动设计(DDD)架构常见的四层架构:
-
基础设施层(Infrastructure Layer): 这一层提供与业务逻辑无关的功能和工具,通常包括实用程序类、工具类、数据库连接、日志记录、缓存、消息队列等。在这一层中,你还可以找到仓储(Repository)接口和数据库访问的实现,用于与持久化存储交互。基础设施层通常是技术相关的,但它们需要被领域层和应用层所依赖。
-
领域层(Domain Layer): 领域层包含了系统的核心业务逻辑。这是应用程序的灵魂,它包括领域模型、实体、值对象、聚合根、领域服务等。这一层与特定的业务领域密切相关,它不包含技术相关的内容,而是关注如何解决业务问题。领域层通常不依赖于其他层,而其他层依赖于领域层。
-
应用层(Application Layer): 应用层位于领域层之上,它是系统的服务层,负责协调领域逻辑的执行。应用层包括应用服务(Application Services),这些服务定义了系统可以执行的各种用例或操作,它们接受来自展示层的请求,协调领域层的操作,处理事务管理,发布领域事件等。应用层通常依赖于基础设施层和领域层。
-
展示层(Presentation Layer): 这是系统与用户或外部系统进行交互的接口层。展示层可以是用户界面(UI)层,如Web界面或移动应用,也可以是API层,用于提供外部系统访问应用程序的接口。展示层通常不直接与领域层交互,而是通过应用层来协调和处理请求。
这种四层架构的分层方法有助于实现领域驱动设计的原则,如分离关注点、保持业务逻辑的纯洁性以及提高系统的可维护性和可扩展性。通过将不同关注点分离到不同的层级,可以更容易地管理和扩展应用程序,同时也使系统的架构更清晰和可维护。
五、系统实现
(一)项目结构
-
Roc.EMall.Infra,即DDD分层中的“基础设施层”,提供一些业务无关的扩展或帮助方法。
-
Roc.EMall.Repository,仓储层(属于基础设施层)负责与数据库交互,通过Dapper和MySql.Data库读取和写入数据到MySQL数据库中。对外仅暴露IRepository及其子接口,隐藏具体实现。
-
Roc.EMall.Domain,领域层包含所有的核心业务,通过充血模型实现业务逻辑。
贫血模型
贫血模型:是指领域对象里只有get和set方法,或者包含少量的CRUD方法,所有的业务逻辑都不包含在内而是放在Business Logic层。
优点是系统的层次结构清楚,各层之间单向依赖,Client->(Business Facade)->Business Logic->Data Access(ADO.NET)。当然Business Logic是依赖Domain Object的。似乎现在流行的架构就是这样,当然层次还可以细分。
该模型的缺点是不够面向对象,领域对象只是作为保存状态或者传递状态使用,所以就说只有数据没有行为的对象不是真正的对象。在Business Logic里面处理所有的业务逻辑,在POEAA(企业应用架构模式)一书中被称为Transaction Script模式。
充血模型
充血模型: 层次结构和上面的差不多,不过大多业务逻辑和持久化放在Domain Object里面,Business Logic只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成Client->(Business Facade)->Business Logic->Domain Object->Data Access。
优点是面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。
参考:充血模型和贫血模型 - 简书
-
Roc.EMall.Application,应用层负责向展示层(WebApi)提供应用服务,调用领域层完成业务功能,协调多个领域对象,调用Repository层完成数据的读取和保存,调用外部接口完成相关验证,发布领域事件。
-
Roc.EMall.WebApi,展示层负责接收用户请求,调用应用层,并返回相关数据给用户。
(二)提交订单功能实现
(三)领域层实现
聚合
聚合Aggregate就是一组相关对象的集合,我们把它作为数据修改和访问的单元。一个聚合包含聚合根、实体和值对象。
每个聚合都会有一个聚合根和聚合的边界Boundary,边界定义了在一个聚合里面内部应该有哪些实体,哪些子实体对象。定义边界的原因是,我们期望对一个聚合的访问是通过聚合根来进行的,聚合里面的子实体对外界是完全封闭的。对于外部对象不应该去访问到一个聚合边界里面的子实体。
按实际对象分析思路,在领域模型中的领域对象分析应该按照从顶向下的思路进行展开,如果这样的话首先识别到的就是聚合根对象,然后再考虑对聚合根对象进行展开,在聚合根对象的展开过程中进一步细化子实体之间的关联和依赖关系。
聚合根、实体、值对象
聚合的特点:高内聚低耦合,是领域模型中最底层的边界,可以作为拆分限界上文的最小单位,一个限界上文可以包含多个聚合,聚合之间的边界是逻辑最天然的边界,有了这个逻辑边界,就可以在微服务拆分的时候作为拆分和组合的依据,推动系统服务化演进。
实体:具有唯一标识(ID),通过ID进行相等性比较,依附于聚合根,生命周期由聚合根来管理。实体和聚合根存在依赖或聚合关系。例如,在Order聚合中,Order类是聚合根,LineItem是实体;
聚合根:聚合根是实体,具备唯一标识,有独立的生命周期,一个聚合只有一个聚合根,聚合根在聚合之内采用引用依赖的方式对实体和值对象进行组织和协调,聚合根和聚合根之间通过唯一id进行聚合之间的协同;
值对象:没有唯一标识(ID),不可变,无生命周期,用完即失效,值对象之间通过属性值判断相等性。值对象的核心是值,是一组概念完整的属性集合,用于描述实体的特征和状态。
为什么要在实体和限界上下文之间增加聚合和聚合根,作用是什么?
在实体和限界上下文之间增加聚合和聚合根的原因是:让实体和值对象协同工作,在实现公共业务逻辑的时候,可以保证数据的一致性。
如何设计聚合?
过程是:通过事件风暴(用例分析,场景分析)得到实体和值对象,然后找出聚合根,按照高内聚低耦合的设计原则,找出跟聚合根紧密关联的实体和值对象,即形成聚合,并画出聚合内的实体和值对象的引用依赖关系,最后把业务关联紧密的聚合画在同一个限界上线文中,即完成了领域建模。
聚合的设计原则: 高内聚,聚合尽量小,聚合之间通过id关联,边界之外使用最终一致性,在应用层实现跨聚合的调用。
(四)Repository层实现
Repository一般是根据领域层中的聚合根维度来划分的。例如,E-Mall系统中,在领域层中Order是聚合根,因此Repsository层中存在对应的OrderRepository,负责Order对象存储和读取工作。
CQRS模式
CQRS — Command Query Responsibility Segregation,故名思义是将 command 与 query 分离的一种模式。
CQRS 将系统中的操作分为两类,即「命令」(Command) 与「查询」(Query)。命令则是对会引起数据发生变化操作的总称,即我们常说的新增,更新,删除这些操作,都是命令。而查询则和字面意思一样,即不会对数据产生变化的操作,只是按照某些条件查找数据。使用CQRS模式,由于将读和写分成两个路径,系统天然地支持读写分离。
在CQRS中,Command直接将数据写入主库(可写),然后通过EventSourcing将变化的数据写入只读库。缺点是,使用EventSourcing增加了系统的复杂度,可能出主库和只读库数据不一致的情况。
在E-Mall项目中,并未采用EventSourcing对主库和只读库进行分离。项目中,在Repository层,将读和写分存两类不同的Repository: IRepository和IQueryRepository,所有Command操作均通过IRepository进行,所有Query操作均通过IQueryRepository操作。
缓存实现
由于采用了CQRS模式,Query Repository和Command Repository是相互独立。因此,缓存只需要在IQueryRepository的实现类上使用装饰者模式,对结果进行缓存即可。对于缓存数据的刷新,只要在对应的Command Repository上也使用装饰者模式即可实现。
Unit Of Work模式
单个Repository只负责维护单个聚合根的读写操作,当一个业务功能需要同时操作多个聚合根,且需要保证数据操作的原子性,那么单个Repository实现起来就比较困难。这时,就需要使用Unit Of Work(工作单元)模式了,Unit Of Work包装了数据库事务,保证多个聚合根操作的原子性。
Unit Of Work(工作单元)模式用来维护一个由已经被业务事物修改(增加、删除或更新)的业务对象组成的列表。Unit Of Work模式负责协调这些修改的持久化工作以及所有标记的并发问题。在数据访问层中采用Unit Of Work模式带来的好处是能够确保数据完整性。如果在持久化一系列业务对象(他们属于同一个事物)的过程中出现问题,那么应该将所有的修改回滚,以确保数据始终处于有效状态。
数据并发更新控制
通常情况,系统先通过Repository从数据库中加载现有数据并构建聚合根对象,应用层调用聚合根的方法执行业务逻辑,更改状态,最后再调用Repository保存到数据库中。
例如,用户提交订单时,应用层服务调用Repository.GetAsync方法获取Sku对象,并调用Sku.Occupy()方法锁定库存,最后再调用Repository.StoreAsync方法保存数据。
在并发较高中的业务场景中,多个用户购买同一个商品时,可能会更出并发锁定库存的现象。为了确保商品不出现“超卖”现象,必须对Sku.Occupy()方法进行并发控制。并发控制方案,一般有两种:
- 乐观并发:适用于并发冲突较少的业务场景,整体效率较高。但是,由于并发时总有一方必定失败,因此需要配合重试机制,提高系统体验。可以通过给数据行增加版本号实现。
- 悲观并发:适用于并发冲突较高的业务场景,并发请求分先后串行执行,整体效率不高。可以通过数据事务隔离级别实现。
E-Mall系统中采用乐观并发控制方案,配合并发重试机制,解决偶发并发失败场景。每个聚合根对象,在从Repository中加载后,都会带上ConVersion字段。更新数据时,将ConVersion字段作为额外的条件。
(五)领域事件实现
领域事件的发布一般放在应用层,通常在事务提交成功之后。领域事件的对象,则由应用层调用聚合根的方法获取,因为领域事件对象属于领域层职责。
在系统中,功能对系统的状态(数据)进行更改后,需要发布领域事件。相关的子系统或模块订阅相关的领域事件,对领域事件做出响应。
例如,对于用户新提交的订单,会要求在30分钟内完成付款,否则订单自动取消,并释放相应的库存。实现这样的功能,一般使用延时队列,30分钟后运行Job检查订单状态,未支付则取消订单,但是这样的逻辑不应该侵入到“提交订单”的业务逻辑中,而应该订阅“新增订单”的领域事件来实现。
六、总结
在我们对E-Mall项目的深度剖析中,似乎不仅仅是一次系统设计的旅程,更是一场关于团队合作与创新的盛宴。从事件风暴的初步探索,到清晰的系统用例,再到领域上下文的精确划分,每一步都像是在绘制一幅复杂而美丽的画卷。
通过引入六边形架构,我们将系统的各个部分有效地分离,确保每个组件都能专注于自己的职责,这就像是将各类食材按照最佳配比精心搭配,使得最终的“菜肴”更加美味可口。而在实现层面,我们通过聚合、仓储模式以及CQRS的运用,让系统不仅在理论上完美,更在实际操作中游刃有余。
当然,在这趟旅程中,我们也得到了对系统实现细节的深刻理解,特别是在面对高并发情况下的乐观和悲观控制策略,让我们的E-Mall不仅能在“厨房”中大显身手,还能在真实的市场环境中应对挑战。
总的来说,E-Mall项目不仅是一段技术探索之旅,更是对团队协作、架构设计和系统实现的全面反思。希望这篇总结能够为你提供灵感,助力你在未来的项目中继续创造出更具竞争力的产品。感谢您的阅读,期待与您在下一个项目中再次相见,共同烹制出更多精彩的“美食”!
相关文章:
EMall实践DDD模拟电商系统总结
目录 一、事件风暴 二、系统用例 三、领域上下文 四、架构设计 (一)六边形架构 (二)系统分层 五、系统实现 (一)项目结构 (二)提交订单功能实现 (三࿰…...
【随笔】AI技术在电商中的应用
这几年,伴随着ChatGPT开始的AI浪潮席卷全球,从聊天场景逐步向多场景扩散,形成了广泛开花的现象。至今,虽然在部分场景的进展已经略显疲态,但当前的这种趋势仍然还在不断的扩展。不少公司,甚至有不少大型电商…...
序列式容器详细攻略(vector、list)C++
vector std::vector 是 STL 提供的 内存连续的、可变长度 的数组(亦称列表)数据结构。能够提供线性复杂度的插入和删除,以及常数复杂度的随机访问。 为什么要使用 vector 作为 OIer,对程序效率的追求远比对工程级别的稳定性要高得多,而 vector 由于其对内存的动态处理,…...
快速启动项目
1 后端项目 https://gitee.com/liuyunkai666/gungun-boot.git 分支: mini 是 springboot3 jdk17 的基础版本,后续其他功能模块陆续在其基础上追加即可。 1.1 必备环境 1.1.1 mysql 创建一个 自定义名称 数据库,【只要】 执行对应数据库…...
springboot347基于web的铁路订票管理系统(论文+源码)_kaic
摘 要 当今社会进入了科技进步、经济社会快速发展的新时代。计算机技术对经济社会发展和人民生活改善的影响也日益突出,人类的生存和思考方式也产生了变化。传统铁路订票管理采取了人工的管理方法,但这种管理方法存在着许多弊端,比如效率低…...
使用API管理Dynadot域名,在账户中添加域名服务器(Name Server)
前言 Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮箱&…...
【Linux | 计网】TCP协议深度解析:从连接管理到流量控制与滑动窗口
目录 前言: 1、三次握手和四次挥手的联系: 为什么挥手必须要将ACK和FIN分开呢? 2.理解 CLOSE_WAIT 状态 CLOSE_WAIT状态的特点 3.FIN_WAIT状态讲解 3.1、FIN_WAIT_1状态 3.2、FIN_WAIT_2状态 3.3、FIN_WAIT状态的作用与意义 4.理解…...
go语言的成神之路-筑基篇-对文件的操作
目录 一、对文件的读写 Reader 接口 Writer接口 copy接口 bufio的使用 ioutil库 二、cat命令 三、包 1. 包的声明 2. 导入包 3. 包的可见性 4. 包的初始化 5. 标准库包 6. 第三方包 7. 包的组织 8. 包的别名 9. 包的路径 10. 包的版本管理 四、go mod 1. 初始…...
两道数据结构编程题
1.写出在顺序存储结构下将线性表逆转的算法,要求使用最少的附加空间。 解:输入:长度为n的线性表数组A(1:n) 输出:逆转后的长度为n的线性表数组A(1:n)。 C语言描述如下(其中ET为数据元素的类型):…...
【Qt】QDateTimeEdit控件实现清空(不保留默认时间/最小时间)
一、QDateTimeEdit控件 QDateTimeEdit 提供了一个用于编辑日期和时间的控件。用户可以通过键盘或使用上下箭头键来增加或减少日期和时间值。日期和时间的显示格式根据设置的格式显示,可以通过 setDisplayFormat() 方法来设置。 二、如何清空 我在使用的时候&#…...
12、字符串
1、字符串概念 字符串用来存储一组字符,因此需要字符数组来存。 C语言中字符串的表示 C语言里面字符串只能用字符数组来存 字符串要求这个数组的末尾必须至少有一个\0 char ch1[] {a,b,c}; // 不是字符串 char ch2[5] {h,e,l,l,o}; // 不是字符串 char…...
DPDK用户态协议栈-Tcp Posix API 1
和udp一样,我们需要实现和系统调用一样的接口来实现我们的tcp server。先来看看我们之前写的unix_tcp使用了哪些接口,这边我加上两个系统调用,分别是接收数据和发送数据。 #include <stdio.h> #include <arpa/inet.h> #include …...
【人工智能-科普】图神经网络(GNN):与传统神经网络的区别与优势
文章目录 图神经网络(GNN):与传统神经网络的区别与优势什么是图神经网络?图的基本概念GNN的工作原理GNN与传统神经网络的不同1. 数据结构的不同2. 信息传递方式的不同3. 模型的可扩展性4. 局部与全局信息的结合GNN的应用领域总结图神经网络(GNN):与传统神经网络的区别与…...
LabVIEW实现UDP通信
目录 1、UDP通信原理 2、硬件环境部署 3、云端环境部署 4、UDP通信函数 5、程序架构 6、前面板设计 7、程序框图设计 8、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利…...
[pdf,epub]228页《分析模式》漫谈合集01-45提供下载
《分析模式》漫谈合集01-45的pdf、epub文件提供下载。已上传至本号的CSDN资源。 如果CSDN资源下载有问题,可到umlchina.com/url/ap.html。 已排版成适合手机阅读,pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》? ★[缝合故事]…...
Kafka的消费消息是如何传递的?
大家好,我是锋哥。今天分享关于【Kafka的消费消息是如何传递的?】面试题。希望对大家有帮助; Kafka的消费消息是如何传递的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中,消息的消费是通过消费…...
二分查找(Java实现)(1)
二分查找(Java实现)(1) leetcode 34.排序数组中查找元素第一个和最后一个位置 题目描述: 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如…...
力扣103.二叉树的锯齿形层序遍历
题目描述 题目链接103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 示例 1ÿ…...
Search with Orama
1.前言 在不久之前,我把 DevNow 的搜索组件通过 Lunr 进行了重构,从前端角度实现了对文章内容的搜索,但是在使用体验上,感觉不是特别好,大概有如下几个原因: 社区的文章数量比较少,项目的 Com…...
一万台服务器用saltstack还是ansible?
一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器,取决于几个关键因素,如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析,帮助你做出决策: SaltStack&…...
计算机类大厂实习春招秋招开发算法面试问答练习题
计算机类大厂实习春招秋招开发算法面试问答练习题 下面有十个非常重要且常问,面试者却注意不到的问题,我们一个个来看,一个个来学。 线程创建到删除过程中,底层是怎么实现的 1.线程创建 线程创建是线程生命周期的起点。在操作系统中,线程可以通过多种方式创建,但无论哪…...
【热门主题】000068 筑牢网络安全防线:守护数字世界的坚实堡垒
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…...
RPC与HTTP调用模式的架构差异
RPC(Remote Procedure Call,远程过程调用)和 HTTP 调用是两种常见的通信模式,它们在架构上有以下一些主要差异: 协议层面 RPC:通常使用自定义的二进制协议,对数据进行高效的序列化和反序列化&am…...
计算机网络之传输层协议UDP
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络之传输层协议UDP 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论💌 目…...
Uniapp 微信小程序内打开web网页
技术栈:Uniapp Vue3 简介 实际业务中有时候会需要在本微信小程序内打开web页面,这时候可以封装一个路由页面专门用于此场景。 在路由跳转的时候携带路由参数,拼接上web url,接收页面进行参数接收即可。 实现 webview页面 新…...
阅读方法论
选择固有缺陷,选项是对比出来的...
373. 查找和最小的 K 对数字
参考的这个博客: https://zhuanlan.zhihu.com/p/457239781 然后看这个代码我想到了另外一种方法,就是一步一步往里加元组 ( i , j ) (i,j) (i,j),看代码就知道了,不过需要做一步去重,去重不能用 i n t [ ] int[] int…...
常用函数的使用错题汇总
目录 new/delete malloc/free1. 语言和类型2. 内存分配3. 内存释放4. 安全性和类型安全5. 其他特性总结 线程停止文件流 new/delete malloc/free malloc/free 和 new/delete 是 C/C 中用于动态内存管理的两种方式,它们有一些重要的区别。以下是这两种方式的比较&…...
uniapp手机端一些坑记录
关于 z-paging-x 组件,在ios上有时候通过弹窗去粗发它reload时会触发闪退,可能是弹框插入进去导致的DOM 元素已经被移除或者不可用,解决办法是加上他自带属性 :showRefresherWhenReload"true" 加上showRefresherWhe…...
2024学习之前端微信小程序开发教程,从入门到精通-含基础+实战+源码code
目录 一、简单介绍 二、课程需知 三、内容编排 1、小程序基础 起步式 目录结构 小程序框架 场景值 逻辑层 视图层 组件 视图容器 基础内容 表单组件 导航 媒体组件 Api 路由 界面 交互 网络 数据缓存 自定义组件 2、项目实战 …...
php开发网站 用java做后台?/优化师培训机构
今天介绍一下django开发中,定义模型时用到的相关字段类型和字段选项。先说说常用的字段类型:1) AutoField: 自增字段类型,当自定义自增类型的id时,可以使用此类型;2) BigAutoField: 64位的整数自增类型;3) BigIntegerF…...
东圃网站建设/国家新闻最新消息今天
应用示例:这里我们假设Master-Slave已经建立。#启动master服务器。[rootStephen-PC redis]# redis-cli -p 6379redis 127.0.0.1:6379>#情况Master当前数据库中的所有Keys。redis 127.0.0.1:6379> flushdbOK#在Master中创建新的Keys作为测试数据。redis 127.0.…...
温岭网站开发/朋友圈信息流广告投放价格
Exchange Server 2016 RTM 可以在 Windows Server 2012、Windows Server 2012 R2 和 Windows Server 2016 的标准版和企业版中进行部署安装,但 Exchange Server 2016 只支持完整 GUI 的 Windows Server 而不支持核心安装的系统,本文我们将对快速部署方式…...
有没有如何做网站的书/可以看封禁网站的浏览器
中国零售巨头阿里巴巴(BABA.US)旗下的云计算部门(简称阿里云),近日开设首家英国数据中心,并在伦敦设有两个运营点。 据了解,英国大区上线了众多云计算产品,包括弹性计算、云存储、数…...
自己怎么做百度网站/深圳网站seo推广
迎接县均衡化国家验收学校解说词办学条件组尊敬的各位专家、各位领导:欢迎莅临我校检查指导工作。我们宁津县第二实验小学始建于1997年,是一所县属非寄宿完全小学。当时只有北面这一座楼,29名教师。2012年秋季扩建,建成南面这座教…...
学校网站的建设费用/百度开户代理
许多外贸公司在选择邮箱时,单次群发量和邮箱容量都是客户选择邮箱品牌的必要条件。小编了解到一些做外贸的公司是需要跟海外的客户发邮件业务往来的,所以,他们需要单次群发量非常高,目前小编了解到,还有一些外贸公司的…...