「领域驱动设计」DDD,六边形架构,洋葱架构,整洁架构和CQRS的整合

这篇文章是软件架构编年史的一部分,一系列关于软件架构的文章。在这些文章中,我写了我对软件架构的了解,我如何看待它,以及我如何使用这些知识。如果您阅读了本系列以前的文章,那么本文的内容可能更有意义。

今天的帖子是关于我如何将所有这些部分组合在一起的,我似乎应该给它起个名字,我称它为显式架构(Explicit Architecture)。此外,这些概念都“通过了它们的考验”,并被用于高要求平台上的生产代码中。一个是SaaS的e-com平台,在全球拥有数千个网络商店,另一个是市场,在两个国家都有一个消息总线,每个月处理超过2000万条消息。

  • 系统的基本模块

  • 工具

  • 将工具和交付机制连接到应用程序核心

    • 端口

    • 主适配器或驱动适配器

    • 辅助或被驱动适配器

    • 控制反转

  • 应用程序的核心组织

    • 域服务

    • 域模型

    • 应用程序层

    • 领域层

  • 组件

    • 组件之间共享的数据存储

    • 每个组件隔离数据存储

    • 解耦的组件

    • 触发逻辑在其他组件

    • 从其他组件获取数据

  • 控制流

系统的基本模块

我首先回顾一下EBI和端口及适配器架构。它们都明确区分了哪些代码是应用程序内部的,哪些是外部的,以及哪些用于连接内部和外部代码。

此外,端口和适配器体系结构明确标识了系统中的三个基本代码块:

  • 是什么使得运行一个用户界面成为可能,不管它是什么类型的用户界面;

  • 系统业务逻辑,或应用程序核心,由用户界面使用,以实际使事情发生;

  • 基础构架代码,它将我们的应用核心与数据库、搜索引擎或第三方api等工具连接起来。

27da7ea5ca3fa8212ca1d4ae4cc5320e.jpeg

应用程序核心是我们真正应该关心的。是代码允许我们的代码做它应该做的事情,是我们的应用程序。它可能使用多个用户界面(渐进式web应用程序、移动应用程序、CLI、API等),但是实际执行工作的代码是相同的,并且位于应用程序内核中,不管什么UI触发它,都应该是一样的。

可以想象,典型的应用程序流从用户界面中的代码开始,通过应用程序核心到基础设施代码,然后返回到应用程序核心,最后向用户界面交付响应。

f1240d2f86116506cd830e42a45cd0cd.jpeg

工具

远离系统中最重要的代码(应用程序核心),我们拥有应用程序使用的工具,例如数据库引擎、搜索引擎、Web服务器或CLI控制台(尽管后两个也是交付机制)。

183efd0d5f773b9f1506fdb6972088b8.jpeg

虽然将CLI控制台与数据库引擎放在同一个“bucket”中可能感觉有些奇怪,尽管它们有不同类型的用途,但它们实际上是应用程序使用的工具。关键的区别在于,虽然CLI控制台和web服务器用于告诉应用程序执行某些操作,但是数据库引擎是由应用程序执行某些操作的。这是一个非常相关的区别,因为它对我们如何构建将这些工具与应用程序核心连接起来的代码有很强的影响。

将工具和传送机制连接到应用程序核心

将工具连接到应用程序核心的代码单元称为适配器(端口和适配器体系结构)。适配器是那些有效地实现代码的适配器,这些代码将允许业务逻辑与特定的工具通信,反之亦然。

告诉我们的应用程序做某事的适配器称为主适配器或驱动适配器,而由我们的应用程序告诉我们做某事的适配器称为辅助适配器或驱动适配器。

端口

然而,这些适配器不是随机创建的。创建它们是为了将特定的入口点安装到应用程序核心(一个端口)。端口只不过是工具如何使用应用程序内核或应用程序内核如何使用它的规范。在大多数语言及其最简单的形式中,这个规范,即端口,将是一个接口,但它实际上可能由几个接口和dto组成。

需要注意的是,端口(接口)属于业务逻辑内部,而适配器属于业务逻辑外部。要使此模式正常工作,最重要的是创建适合应用程序核心需求的端口,而不是简单地模仿工具api。

主适配器或驱动适配器

主适配器或驱动适配器围绕一个端口,并使用它来告诉应用程序核心要做什么。它们将来自交付机制的任何东西转换为应用程序核心中的方法调用。

ccb76fc2acd2a37a08b3decadb8fef70.jpeg

换句话说,我们的驱动适配器是控制器或控制台命令,它们在构造函数中注入一些对象,这些对象的类实现控制器或控制台命令所需的接口(端口)。

在更具体的示例中,端口可以是控制器所需的服务接口或存储库接口。然后将服务、存储库或查询的具体实现注入并在控制器中使用。

或者,端口可以是命令总线或查询总线接口。在这种情况下,将命令或查询总线的具体实现注入控制器,然后控制器构造命令或查询并将其传递给相关总线。

辅助或被驱动适配器

与围绕端口的被驱动适配器不同,驱动适配器实现一个端口和一个接口,然后将其注入到应用程序核心中,无论哪里需要端口(类型暗示)。

c0117550ac5734d8855fe193f172a15a.jpeg

例如,假设我们有一个需要持久化数据的简单应用程序。所以我们创建一个持久性接口,满足其需要,用一个方法来保存数组的数据和方法来删除表中的一行的ID。从那时起,无论应用程序需要保存或删除数据,我们需要在其构造函数实现持久化的对象我们定义的接口。

现在我们创建一个特定于MySQL的适配器来实现这个接口。它将具有保存数组和删除表中的一行的方法,并且我们将在需要持久性接口的地方注入它。

如果在某个时候我们决定改变数据库供应商,比如PostgreSQL或MongoDB,我们只需要创建一个新的适配器来实现PostgreSQL特定的持久化接口,并注入新的适配器而不是旧的。

控制反转

关于此模式需要注意的一个特征是,适配器依赖于特定的工具和特定的端口(通过实现接口)。但是我们的业务逻辑只依赖于端口(接口),它被设计成适合业务逻辑需求,所以它不依赖于特定的适配器或工具。

f0bce0223e85492aeaf63d1e73cff61b.jpeg

这意味着依赖的方向是朝向中心的,这是建筑层面的控制原则的倒置。

尽管如此,创建端口是为了满足应用程序的核心需求,而不是简单地模仿工具api,这一点非常重要。

应用程序的核心组织

Onion架构采用DDD层,并将它们合并到端口和适配器架构中。这些层旨在为业务逻辑、端口和适配器的内部“六边形”带来一些组织,就像端口和适配器一样,依赖关系的方向是向中心的。

应用程序层

用例是可以由应用程序中的一个或多个用户接口在应用程序核心中触发的流程。例如,在CMS中,我们可以有普通用户使用的实际应用程序UI、CMS管理员使用的另一个独立UI、另一个CLI UI和web API。这些ui(应用程序)可以触发特定于其中一个或由其中几个重用的用例。

用例在应用层中定义,这是DDD提供的第一层,由Onion Architecture使用。

fe7a27b194efe7ace060ce2ef0310ec7.jpeg

这一层包含作为第一类公民的应用程序服务(及其接口),但它也包含端口和适配器接口(端口),其中包括ORM接口、搜索引擎接口、消息传递接口等等。在我们使用命令总线和/或查询总线的情况下,这一层是命令和查询各自的处理程序所在的地方。

应用程序服务和/或命令处理程序包含展开用例(业务流程)的逻辑。一般来说,他们的职责是:

  • 使用存储库查找一个或多个实体;

  • 告诉那些实体去做一些域逻辑;

  • 并使用存储库再次持久化实体,有效地保存数据更改。

命令处理程序可以用两种不同的方式使用:

  • 它们可以包含执行用例的实际逻辑;

  • 它们可以在我们的体系结构中用作简单的连接块,接收命令并简单地触发存在于应用程序服务中的逻辑。

使用哪种方法取决于上下文,例如:

我们是否已经准备好了应用程序服务并正在添加命令总线?

命令总线是否允许指定任何类/方法作为处理程序,或者它们是否需要扩展或实现现有的类或接口?

这一层还包含应用程序事件的触发,这些事件表示用例的一些结果。这些事件触发的逻辑是用例的副作用,比如发送电子邮件、通知第三方API、发送推送通知,甚至启动属于应用程序不同组件的另一个用例。

领域层

再往里,我们有域层。这个层中的对象包含数据和操作数据的逻辑,这是特定于域本身的,它独立于触发逻辑的业务流程,它们是独立的,完全不知道应用层。

a8de2a91dec741b2630fef7863573534.jpeg

域服务

如前所述,应用服务的作用是:

  • 使用存储库查找一个或多个实体;

  • 告诉那些实体去做一些域逻辑;

  • 并使用存储库再次持久化实体,有效地保存数据更改。

然而,有时我们会遇到一些涉及不同实体的域逻辑,不管它们是否属于同一类型,我们觉得域逻辑不属于实体本身,我们觉得那个逻辑不是它们的直接责任。

因此,我们的第一反应可能是将逻辑放在实体之外的应用程序服务中。然而,这意味着该域逻辑将不能在其他用例中重用:域逻辑应该远离应用程序层!

解决方案是创建一个域服务,它的角色是接收一组实体并在其上执行一些业务逻辑。域服务属于域层,因此它对应用层中的类一无所知,比如应用程序服务或存储库。另一方面,它可以使用其他域服务,当然还有域模型对象。

域模型

在最中心的是域模型,它不依赖于它之外的任何东西,它包含表示域内某些内容的业务对象。这些对象的示例首先是实体,但也包括值对象、枚举和域模型中使用的任何对象。

域模型也是域事件“活动”的地方。当特定的一组数据发生更改时,将触发这些事件,并将这些更改随身携带。换句话说,当一个实体发生更改时,将触发一个域事件,它将携带更改后的属性新值。例如,这些事件非常适合用于事件源。

组件

到目前为止,我们一直在基于层隔离代码,但这是细粒度的代码隔离。粗粒度的代码隔离至少是同样重要的,它是根据子域和有界上下文来隔离代码的,遵循Robert C. Martin在尖叫声架构中表达的思想。这通常被称为“按功能包”或“按组件包”,而不是“按层包”,Simon Brown在他的博客“按组件包和体系结构对齐测试”中对此做了很好的解释:

4f77e59792965c18c3d95a43de8ef0d3.jpeg

我是“按组件打包”方法的倡导者,并且根据Simon Brown关于按组件打包的图表,我将无耻地将其更改为以下内容:

f3463fa6624d93d15ed87acb475e664c.jpeg

这些代码部分与前面描述的层是交叉的,它们是我们的应用程序的组件。组件的示例可以是身份验证、授权、计费、用户、审查或帐户,但它们始终与域相关。像授权和/或身份验证这样的有界上下文应该被视为外部工具,我们为其创建适配器并隐藏在某种端口之后。

311d7d4f3b58f8e7835e83f65cd43811.jpeg

解耦的组件

就像细粒度的代码单元(类、接口、特征、混合等)一样,粗粒度的代码单元(组件)也受益于低耦合和高内聚。

为了解耦类,我们使用依赖注入,将依赖注入到类中而不是在类中实例化,依赖倒置,使类依赖于抽象(接口和/或抽象类)而不是具体类。这意味着子类不知道它将要使用的具体类,它没有引用它所依赖的类的完全限定类名。

同样,完全解耦的组件意味着一个组件不直接知道任何其他组件。换句话说,它没有引用来自另一个组件的任何细粒度代码单元,甚至没有接口!这意味着依赖注入和依赖倒置不足以解耦组件,我们需要某种架构结构。我们可能需要事件、共享内核、最终一致性,甚至发现服务!

f1042ffd0890240a4309f73ee02a6cf8.jpeg

在其他组件触发逻辑

当我们的一个组件(组件B)需要在另一个组件(组件A)中发生其他事情时执行某个操作时,我们不能简单地从组件A直接调用组件B中的类/方法,因为这样A就会被耦合到B。

然而,我们可以使用事件分派器来分派一个应用程序事件,该应用程序事件将被交付给监听它的任何组件,包括B,而B中的事件侦听器将触发所需的操作。这意味着组件A将依赖于事件分配器,但它将与B解耦。

然而,如果事件本身“存在”于A中,这意味着B知道A的存在,它与A是耦合的。这意味着组件都依赖于共享内核,但是它们之间是解耦的。共享内核将包含应用程序和域事件之类的功能,但它也可以包含规范对象,以及任何需要共享的内容,请记住,共享内核的任何更改都将影响到应用程序的所有组件,因此共享内核应该尽可能少。此外,如果我们有一个多语言系统,假设是一个微服务生态系统,其中它们是用不同的语言编写的,那么共享内核需要是语言无关的,以便所有组件都可以理解它,无论它们是用什么语言编写的。例如,它将包含事件描述,而不是包含事件类的共享内核。名称、属性、甚至方法(尽管这些在JSON之类的不可知语言中可能更有用),这样所有组件/微服务都可以解释它,甚至自动生成它们自己的具体实现。请在我的后续文章中相关内容:不仅仅是同心圆层。

ef16f4b04c2fb87608446a0df6bb5391.jpeg

这种方法既适用于单片应用程序,也适用于像微服务生态系统这样的分布式应用程序。然而,当事件只能异步交付时,对于需要立即在其他组件中执行触发逻辑的上下文,这种方法是不够的!组件将需要一个直接的HTTP调用组件b。在这种情况下,解耦的组件,我们需要发现服务,将要求它应该发送请求来启动所需的行动,或者使请求发现服务代理的相关服务,最终将响应返回给请求者。此方法将把组件耦合到发现服务,但将使它们彼此解耦。

从其他组件获取数据

在我看来,一个组件不允许改变它不“拥有”的数据,但是它可以查询和使用任何数据。

组件之间共享的数据存储

当一个组件需要使用属于另一个组件的数据时,假设一个账单组件需要使用属于accounts组件的客户端名称,账单组件将包含一个查询对象,该对象将查询该数据的数据存储。这仅仅意味着账单组件可以知道任何数据集,但是它必须通过查询的方式将不“拥有”的数据作为只读数据使用。

每个组件隔离数据存储

在本例中,应用了相同的模式,但是我们在数据存储级别上更加复杂。组件拥有自己的数据存储意味着每个数据存储包含:

  • 它拥有的一组数据,并且是唯一允许更改的数据,使其成为唯一的真理来源;

  • 一组数据是其他组件数据的副本,它不能自己更改这些数据,但是组件功能需要它,并且需要在所有者组件中发生更改时对其进行更新。

每个组件将从其他组件创建所需数据的本地副本,以便在需要时使用。当拥有该组件的组件中的数据发生更改时,该所有者组件将触发承载数据更改的域事件。持有该数据副本的组件将侦听该域事件,并相应地更新其本地副本。

控制流

正如我上面所说的,控制流当然是从用户到应用程序核心,再到基础设施工具,最后回到应用程序核心,最后回到用户。但是类到底是如何组合在一起的呢?哪些取决于哪些?我们如何组合它们?

在Bob叔叔关于干净架构的文章中,我将尝试用UMLish图来解释控制流……

没有命令/查询总线

在我们不使用命令总线的情况下,控制器将依赖于应用程序服务或查询对象。

787d3d2be18a79d95ca6b8aedaf4a514.jpeg

在上面的图中我们使用应用程序的接口服务,尽管我们可能认为这不是真正需要从应用程序服务是我们应用程序代码的一部分,我们不会想交换另一个实现,尽管我们可能完全重构它。

查询对象将包含一个优化的查询,该查询将简单地返回一些原始数据以显示给用户。该数据将以DTO的形式返回,并注入到ViewModel中。这个视图模型可能有一些视图逻辑,它将被用来填充一个视图。

另一方面,应用程序服务将包含用例逻辑,当我们希望在系统中执行某些操作时,而不是简单地查看某些数据时,将触发该逻辑。应用程序服务依赖于存储库,存储库将返回包含需要触发的逻辑的实体。它还可能依赖于域服务来协调多个实体中的域流程,但情况并非如此。

在展开用例之后,应用程序服务可能希望通知整个系统该用例已经发生,在这种情况下,它还将依赖于事件分派器来触发事件。

值得注意的是,我们在持久性引擎和存储库上都放置了接口。虽然看起来有些多余,但它们有不同的用途:

  • 持久性接口是ORM上的一个抽象层,因此我们可以交换正在使用的ORM,而不需要更改应用程序的核心。

  • repository接口是对持久性引擎本身的抽象。假设我们想从MySQL切换到MongoDB。持久性接口可以是相同的,如果我们想继续使用相同的ORM,那么即使是持久性适配器也可以保持不变。但是,查询语言是完全不同的,所以我们可以创建使用相同持久性机制的新存储库,实现相同的存储库接口,但是使用MongoDB查询语言而不是SQL构建查询。

使用命令/查询总线

在我们的应用程序使用命令/查询总线的情况下,除了控制器现在依赖于总线和命令或查询外,关系图几乎保持不变。它将实例化命令或查询,并将其传递给总线,总线将找到适当的处理程序来接收和处理命令。

在下面的关系图中,命令处理程序然后使用应用程序服务。然而,这并不总是需要的,事实上在大多数情况下,处理程序将包含用例的所有逻辑。如果需要在另一个处理程序中重用相同的逻辑,则只需要将逻辑从处理程序提取到单独的应用程序服务中。

51fec80b67cdf9f1a6329da8505fb0bc.jpeg

您可能已经注意到,总线与命令、查询和处理程序之间没有依赖关系。这是因为,为了提供良好的解耦,它们实际上应该彼此不了解。总线知道什么处理程序应该处理什么命令或查询的方式应该通过简单的配置来设置。

如您所见,在这两种情况下,跨越应用程序核心边界的所有箭头和依赖项都指向内部。如前所述,这是端口和适配器体系结构、Onion体系结构和Clean体系结构的基本规则。

0be130230e98769b6d3579e2e6e91dd3.jpeg

结论

一如既往,我们的目标是拥有一个松散耦合和高内聚的代码库,这样修改起来就容易、快速和安全。

计划是没有价值的,但计划就是一切。
-------------------------------艾森豪威尔

这个信息图是一个概念图。了解和理解所有这些概念将帮助我们规划一个健康的架构,一个健康的应用程序。

然而:

地图不是领土。
-----------------------阿尔弗雷德Korzybski

这意味着这些只是指导方针!应用程序是我们需要应用知识的领域、现实和具体用例,这就是定义实际体系结构的内容!

我们需要理解所有这些模式,但是为了解耦和内聚,我们还需要思考并准确地理解我们的应用程序需要什么,我们应该走多远。这个决策可以依赖于许多因素,从项目功能需求开始,但是也可以包括诸如构建应用程序的时间框架、应用程序的生命周期、开发团队的经验等因素。

就是这样,这就是我理解这一切的方式。这就是我在脑海里给它找的合理解释。

我在后续的文章中进一步扩展了这些想法:不仅仅是同心圆层。

但是,我们如何在代码库中显式地实现这一切呢?这是我下一篇文章的主题:如何在代码中反映体系结构和域。

本文 :https://architect.pub/ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together
讨论:知识星球【首席架构师圈】或者加微信小号【ca_cto】或者加QQ群【792862318】
公众号

【jiagoushipro】
【超级架构师】
精彩图文详解架构方法论,架构实践,技术原理,技术趋势。
我们在等你,赶快扫描关注吧。
ef20cff48523b6f4a2756c023ef164b8.jpeg
微信小号

【ca_cea】
50000人社区,讨论:企业架构,云计算,大数据,数据科学,物联网,人工智能,安全,全栈开发,DevOps,数字化.

a5f621f432e26c65fa18e64eafd9e37f.jpeg

QQ群

【285069459】深度交流企业架构,业务架构,应用架构,数据架构,技术架构,集成架构,安全架构。以及大数据,云计算,物联网,人工智能等各种新兴技术。
加QQ群,有珍贵的报告和干货资料分享。

e39b23204d8495aac32144e39319978e.jpeg

视频号【超级架构师】
1分钟快速了解架构相关的基本概念,模型,方法,经验。
每天1分钟,架构心中熟。

6812be4cde024ebfa2d3c55cbedf96cc.jpeg

知识星球【首席架构师圈】向大咖提问,近距离接触,或者获得私密资料分享。

d6f349ab5e395cace1e8d0e9e35db7bc.jpeg

喜马拉雅【超级架构师】路上或者车上了解最新黑科技资讯,架构心得。【智能时刻,架构君和你聊黑科技】
知识星球认识更多朋友,职场和技术闲聊。知识星球【职场和技术】
领英Harryhttps://www.linkedin.com/in/architect-harry/
领英群组领英架构群组
https://www.linkedin.com/groups/14209750/
微博‍‍【超级架构师】智能时刻‍
哔哩哔哩【超级架构师】

70f539d8dc189e2640e773118b930f3a.jpeg

抖音【cea_cio】超级架构师

d0cf165dd3e0dd95bd3fb2ca1217c27a.jpeg

快手【cea_cio_cto】超级架构师

bd6426e31d1831566bc641778eafe5b4.jpeg

小红书【cea_csa_cto】超级架构师

2ea0389912628454eb2b45a3bb930cee.jpeg

网站CIO(首席信息官)https://cio.ceo
网站CIO,CTO和CDOhttps://cioctocdo.com
网站架构师实战分享https://architect.pub   
网站程序员云开发分享https://pgmr.cloud
网站首席架构师社区https://jiagoushi.pro
网站应用开发和开发平台https://apaas.dev
网站开发信息网https://xinxi.dev
网站超级架构师https://jiagou.dev
网站企业技术培训https://peixun.dev
网站程序员宝典https://pgmr.pub    
网站开发者闲谈https://blog.developer.chat
网站CPO宝典https://cpo.work
网站首席安全官https://cso.pub    ‍
网站CIO酷https://cio.cool
网站CDO信息https://cdo.fyi
网站CXO信息https://cxo.pub

谢谢大家关注,转发,点赞和点在看。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/17789.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【多任务学习】Multi-task Learning 手把手编码带数据集, 一文吃透多任务学习

文章目录 前言1.多任务学习1.1 定义1.2 原理 2. 多任务学习code2.1 数据集初探2.2 预处理2.3 网络结构2.4 训练 3. 总结 前言 我们之前讲过的模型通常聚焦单个任务,比如预测图片的类别等,在训练的时候,我们会关注某一个特定指标的优化. 但是有时候,我们需要知道一个图片,从它身…

PostgreSQL 基础知识:psql 提示和技巧

对于积极使用和连接到 PostgreSQL 数据库的任何开发人员或 DBA 来说,能够访问psql命令行工具是必不可少的。在我们的第一篇文章中,我们讨论了 psql的简要历史,并演示了如何在您选择的平台上安装它并连接到 PostgreSQL 数据库。 在本文中&…

HTTPS协议介绍

文章目录 一、HTTPS协议的认识二、常见的加密方式1.对称加密2.非对称加密 三、数据摘要四、HTTPS的工作过程探究1.只使用对称加密2.只使用非对称加密3.双方都使用非对称加密4.非对称加密对称加密5.中间人攻击6.引入证书7.非对称加密对称加密证书认证 一、HTTPS协议的认识 HTTP…

HTTP的method方法 GET POST PUT DELETE HEAD OPTIONS CONNECT PATCH TRACE

HTTP的method方法 GET POST PUT DELETE HEAD OPTIONS CONNECT PATCH TRACE GET 向指定的资源发出“显示”请求。使用GET方法应该只用在读取数据,而不应当被用于产生“副作用”的操作中,例如在Web Application中。其中一个原因是GET可能会被网络蜘蛛等随意…

Docker 持久化存储 Bind mounts

Docker 持久化存储 Bind mounts Bind mounts 的 -v 与 --mount 区别启动容器基于bind mount挂载到容器中的非空目录只读 bind mountcompose 中使用 bind mount 官方文档:https://docs.docker.com/storage/bind-mounts/ Bind mounts 的 -v 与 --mount 区别 如果使用…

ePWM模块(1)

ePWM模块 ePWM模块内部包含有7个子模块,分别是时间基准子模块TB、比较功能子模块CC,动作限定子模块AQ、死区控制子模块DB、斩波控制子模块PC、事件触发子模块ET和故障捕获子模块TZ。 每个ePWM模块都具有以下功能: 可以输出两路PWM,EPWMxA和EPWMxB两路PWM可以独立输出,也可…

大二一个学期学这么点内容,没有概念,只有实操

如何查看所有的数据库: Show databases; 如何进入某个数据库: use xxx; 如何新进数据库: Create database jx; 如何删除数据库: Drop database jx; 如何查看所有的表格: Show tables; 如何创建数据表&#xf…

【Flink】DataStream API使用之执行环境

1. 执行环境 Flink 程序可以在各种上下文环境中运行:我们可以在本地 JVM 中执行程序,也可以提交 到远程集群上运行。不同的环境,代码的提交运行的过程会有所不同。这就要求我们在提交作业执行计算时,首先必须获取当前 Flink 的运…

(异或相消)猫猫数字异或和

E - Red Scarf (atcoder.jp) 刚入坑写的一道题被我拉出来对比分析了 我的思路: 垃圾运气选手凭借直觉乱搞猜出来的,没有思路。 题解思路: 由问题陈述中XOR的定义,我们可以看出计算3个或更多整数的XOR可以以任意顺序进行&#…

ChatGPT :十几个国内免费可用 ChatGPT 网页版

前言 ChatGPT(全名:Chat Generative Pre-trained Transformer),美国OpenAI 研发的聊天机器人程序 ,于2022年11月30日发布 。ChatGPT是人工智能技术驱动的自然语言处理工具,它能够通过理解和学习人类的语言…

树脂塞孔有哪些优缺点及应用?

树脂塞孔的概述 树脂塞孔就是利用导电或者非导电树脂,通过印刷,利用一切可能的方式,在机械通孔、机械盲埋孔等各种类型的孔内进行填充,实现塞孔的目的。 树脂塞孔的目的 1 树脂填充各种盲埋孔之后,利于层压的真空下…

盲目自学网络安全只会成为脚本小子?

前言:我们来看看怎么学才不会成为脚本小子 目录: 一,怎么入门? 1、Web 安全相关概念(2 周)2、熟悉渗透相关工具(3 周)3、渗透实战操作(5 周)4、关注安全圈动…

2.RabbitMQ

RabbitMQ 1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式: 同步通讯:就像打电话,需要实时响应。 异步通讯:就像发邮件,不需要马上回复。 两种方式各有优劣,打电话可以立即得到响应&am…

springboot整合flowable工作流引擎的简单使用

内容来自网络整理,文章最下有引用地址,可跳转至相关资源页面。若有侵权请联系删除 环境: mysql5.7.2 springboot 2.3.9.RELEASE flowable 6.7.2 采坑: 1.当前flowable sql需要与引用的pom依赖一致,否则会报library…

进程/线程 状态模型详解

前言:最近操作系统复习到线程的状态模型(也可以说进程的状态模型,本文直接用线程来说)时候,网上查阅资料,发现很多文章都说的很不一样,有五状态模型、六状态模型、七状态模型.......虽然都是对的…

[Python]爬虫基础——urllib库

urllib目录 一、简介二、发送请求1、urlopen()函数2、Request()函数 三、异常处理四、解析URL五、分析Robots协议 一、简介 urllib库是Python内置的标准库。包含以下四个模块: 1、request:模拟发送HTTP请求; 2、error:处理HTTP请…

前端技术——css

1.CSS的引入 【1】为什么要学习CSS? 如果只用HEML画页面的话--->这个页面就是页面上需要的元素罗列起来,但是页面效果很差,不好看,为了让页面好看,为了修饰页面。所以我们需要用到CSS。 CSS的作用:修饰HTML页面…

linux操作手册

开机&关机 指令 shutdown -h now 立刻进行关机 shutdown -h num num分钟后执行关机 shutdown -r now 现在重启计算机 halt 关机 rebboot 重启计算机 sync 把内存的数据同步到磁盘 注意事项 无论是重启还是关闭系统,都必须先执行sync,将内存…

使用无标注的数据训练Bert

文章目录 1、准备用于训练的数据集2、处理数据集3、克隆代码4、运行代码5、将ckpt模型转为bin模型使其可在pytorch中运用 Bert官方仓库:https://github.com/google-research/bert 1、准备用于训练的数据集 此处准备的是BBC news的数据集,下载链接&…

camunda表达式如何使用

在Camunda中,表达式是一种灵活的方式,可以用于在流程定义和表单中计算和处理数据。表达式可以在Camunda的各个环节中使用,例如服务任务、网关、表单、条件等。 以下是Camunda表达式的一些常见用途: 1、计算值:表达式可…