Spring Boot集成statemachine快速入門demo

1.什么是statemachine?

Spring Statemachine 是應用程序開發人員在 Spring 應用程序中使用狀態機概念的框架,從設計層面分析:狀態機目的是解決復雜的狀態管理流程,保證程序單一原則和開閉原則;業務角度分析:狀態機應有初始化狀態、加載所有已有的狀態、事件、轉移、動作、觸發下一個狀態為驅動,并解決了業務邏輯與狀態管理之間的強耦合。

Spring Statemachine?提供以下功能:

  • 易于使用的平面(一級)狀態機,適用于簡單的用例。
  • 分層狀態機結構,以簡化復雜的狀態配置。
  • 狀態機區域提供更復雜的狀態配置。
  • 觸發器、轉換、守衛和動作的使用。
  • 類型安全的配置適配器。
  • 狀態機事件監聽器。
  • Spring IoC 集成將 bean 與狀態機相關聯。

Spring Statemachine 原理

Spring狀態機建立在有限狀態機(FSM)的概念之上,提供了一種簡潔且靈活的方式來定義、管理和執行狀態機。它將狀態定義為Java對象,并通過配置來定義狀態之間的轉換規則。狀態轉換通常由外部事件觸發,我們可以根據業務邏輯定義不同的事件類型,并與狀態轉換關聯。Spring狀態機還提供了狀態監聽器,用于在狀態變化時執行特定的邏輯。同時,狀態機的狀態可以持久化到數據庫或其他存儲介質中,以便在系統重啟或故障恢復時保持狀態的一致性。 Spring狀態機核心主要包括以下三個關鍵元素:

  1. 狀態(State):定義了系統可能處于的各個狀態,如訂單狀態中的待支付、已支付等。
  2. 轉換(Transition):描述了在何種條件下,當接收到特定事件時,系統可以從一個狀態轉移到另一個狀態。例如,接收到“支付成功”事件時,訂單狀態從“待支付”轉變為“已支付”。
  3. 事件(Event):觸發狀態轉換的動作或者消息,它是引起狀態機從當前狀態遷移到新狀態的原因。

接下來,我們將上述狀態模式中關于訂單狀態的示例轉換為狀態機實現。 ?

2.代碼工程

實驗目標:訂單狀態的示例轉換為狀態機實現。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Statemachine</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>2.0.0.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
</project>

定義狀態機的狀態以及事件類型

定義狀態(States): 狀態是狀態機的核心組成單元,代表了系統或對象在某一時刻可能存在的條件或模式。在狀態機中,每一個狀態都是系統可能處于的一種明確的條件或階段。例如,在一個簡單的咖啡機狀態機中,可能有的狀態包括“待機”、“磨豆”、“沖泡”和“完成”。每個狀態都是獨一無二的,且在任何給定時間,系統只能處于其中一個狀態。?定義轉換(Transitions): 轉換則是指狀態之間的轉變過程,它是狀態機模型動態性的體現。當一個外部事件(如用戶按下按鈕、接收到信號、滿足特定條件等)觸發時,狀態機會從當前狀態轉移到另一個狀態。在定義轉換時,需要指出觸發轉換的事件(Event)以及事件發生時系統的響應,即從哪個狀態(Source State)轉到哪個狀態(Target State)。

package com.et.statemachine.state;/*** @description:order status*/
public enum OrderStatusChangeEventEnum {PAYED,DELIVERY,RECEIVED;
}
package com.et.statemachine.state;/*** @description: order status*/
public enum OrderStatusEnum {WAIT_PAYMENT,WAIT_DELIVER,WAIT_RECEIVE,FINISH;
}

定義狀態機以及狀態流轉規則

狀態機配置類是在使用Spring State Machine或其他狀態機框架時的一個重要步驟,這個類主要用于定義狀態機的核心結構,包括狀態(states)、事件(events)、狀態之間的轉換規則(transitions),以及可能的狀態遷移動作和決策邏輯。 在Spring State Machine中,創建狀態機配置類通常是通過繼承StateMachineConfigurerAdapter類來實現的。這個適配器類提供了幾個模板方法,允許開發者重寫它們來配置狀態機的各種組成部分:

  1. 配置狀態configureStates(StateMachineStateConfigurer)): 在這個方法中,開發者定義狀態機中所有的狀態,包括初始狀態(initial state)和結束狀態(final/terminal states)。例如,定義狀態A、B、C,并指定狀態A作為初始狀態。
  2. 配置轉換configureTransitions(StateMachineTransitionConfigurer)): 在這里,開發者描述狀態之間的轉換規則,也就是當某個事件(event)發生時,狀態機應如何從一個狀態轉移到另一個狀態。例如,當事件X發生時,狀態機從狀態A轉移到狀態B。
  3. 配置初始狀態configureInitialState(ConfigurableStateMachineInitializer)): 如果需要顯式指定狀態機啟動時的初始狀態,可以在該方法中設置。
package com.et.statemachine.config;import com.et.statemachine.state.OrderStatusChangeEventEnum;
import com.et.statemachine.state.OrderStatusEnum;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.EnumSet;/*** @description: order statemachine*/
@Configuration
@EnableStateMachine
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {/*** configure state*/@Overridepublic void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> states) throws Exception {states.withStates().initial(OrderStatusEnum.WAIT_PAYMENT).end(OrderStatusEnum.FINISH).states(EnumSet.allOf(OrderStatusEnum.class));}/*** configure state transient  with event*/@Overridepublic void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> transitions) throws Exception {transitions.withExternal().source(OrderStatusEnum.WAIT_PAYMENT).target(OrderStatusEnum.WAIT_DELIVER).event(OrderStatusChangeEventEnum.PAYED).and().withExternal().source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE).event(OrderStatusChangeEventEnum.DELIVERY).and().withExternal().source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.FINISH).event(OrderStatusChangeEventEnum.RECEIVED);}
}

定義狀態機監聽器

狀態機監聽器(State Machine Listener)是一種組件,它可以監聽并響應狀態機在運行過程中的各種事件,例如狀態變遷、進入或退出狀態、轉換被拒絕等。 在Spring Statemachine中,監聽器可以通過實現StateMachineListener接口來定義。該接口提供了一系列回調方法,如transitionTriggeredstateEnteredstateExited等,當狀態機觸發轉換、進入新狀態或離開舊狀態時,這些方法會被調用。同時,我們也可以通過注解實現監聽器。注解方式可以在類的方法上直接聲明該方法應該在何種狀態下被調用,簡化監聽器的編寫和配置。例如@OnTransition@OnTransitionEnd@OnTransitionStart

package com.et.statemachine.listener;import com.et.statemachine.state.Order;
import com.et.statemachine.state.OrderStatusEnum;
import org.springframework.messaging.Message;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;/*** @description: state listener*/
@Component
@WithStateMachine
@Transactional
public class OrderStatusListener {@OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER")public boolean payTransition(Message message) {Order order = (Order) message.getHeaders().get("order");order.setOrderStatus(OrderStatusEnum.WAIT_DELIVER);System.out.println("pay,feedback by statemachine:" + message.getHeaders().toString());return true;}@OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")public boolean deliverTransition(Message message) {Order order = (Order) message.getHeaders().get("order");order.setOrderStatus(OrderStatusEnum.WAIT_RECEIVE);System.out.println("deliver,feedback by statemachine:" + message.getHeaders().toString());return true;}@OnTransition(source = "WAIT_RECEIVE", target = "FINISH")public boolean receiveTransition(Message message) {Order order = (Order) message.getHeaders().get("order");order.setOrderStatus(OrderStatusEnum.FINISH);System.out.println("receive,feedback by statemachine:" + message.getHeaders().toString());return true;}}

service

package com.et.statemachine.service;import com.et.statemachine.state.Order;import java.util.Map;/*** @author liuhaihua* @version 1.0* @ClassName OrderService* @Description todo* @date 2024年05月27日 15:15*/public interface OrderService {Order create();Order pay(long id);Order deliver(long id);Order receive(long id);Map<Long, Order> getOrders();
}
package com.et.statemachine.service;import com.et.statemachine.state.Order;
import com.et.statemachine.state.OrderStatusChangeEventEnum;
import com.et.statemachine.state.OrderStatusEnum;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;/*** @description: order service*/
@Service
public class OrderServiceImpl implements OrderService {@Resourceprivate StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;private long id = 1L;private Map<Long, Order> orders = new ConcurrentHashMap<>();@Overridepublic Order create() {Order order = new Order();order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT);order.setOrderId(id++);orders.put(order.getOrderId(), order);System.out.println("order create success:" + order.toString());return order;}@Overridepublic Order pay(long id) {Order order = orders.get(id);System.out.println("try to pay,order no:" + id);Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED).setHeader("order", order).build();if (!sendEvent(message)) {System.out.println(" pay fail, error,order no:" + id);}return orders.get(id);}@Overridepublic Order deliver(long id) {Order order = orders.get(id);System.out.println(" try to deliver,order no:" + id);if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.DELIVERY).setHeader("order", order).build())) {System.out.println(" deliver fail,error,order no:" + id);}return orders.get(id);}@Overridepublic Order receive(long id) {Order order = orders.get(id);System.out.println(" try to receiver,order no:" + id);if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.RECEIVED).setHeader("order", order).build())) {System.out.println(" deliver fail,error,order no:" + id);}return orders.get(id);}@Overridepublic Map<Long, Order> getOrders() {return orders;}/*** send transient  event* @param message* @return*/private synchronized boolean sendEvent(Message<OrderStatusChangeEventEnum> message) {boolean result = false;try {orderStateMachine.start();result = orderStateMachine.sendEvent(message);} catch (Exception e) {e.printStackTrace();} finally {if (Objects.nonNull(message)) {Order order = (Order) message.getHeaders().get("order");if (Objects.nonNull(order) && Objects.equals(order.getOrderStatus(), OrderStatusEnum.FINISH)) {orderStateMachine.stop();}}}return result;}
}

controller

package com.et.statemachine.controller;import com.et.statemachine.service.OrderService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;@RestController
public class HelloWorldController {@RequestMapping("/hello")public Map<String, Object> showHelloWorld(){Map<String, Object> map = new HashMap<>();map.put("msg", "HelloWorld");return map;}@Resourceprivate OrderService orderService;@RequestMapping("/testOrderStatusChange")public String testOrderStatusChange(){orderService.create();orderService.create();orderService.pay(1L);orderService.deliver(1L);orderService.receive(1L);orderService.pay(2L);orderService.deliver(2L);orderService.receive(2L);System.out.println("all orders:" + orderService.getOrders());return "success";}}

以上只是一些關鍵代碼,所有代碼請參見下面代碼倉庫

代碼倉庫

  • GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.

3.測試

啟動Spring Boot應用

測試狀態機

訪問http://127.0.0.1:8088/testOrderStatusChange,查看控制臺輸出

order create success:Order(orderId=1, orderStatus=WAIT_PAYMENT)
order create success:Order(orderId=2, orderStatus=WAIT_PAYMENT)
try to pay,order no:1
2024-05-27 22:58:14.208 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : started org.springframework.statemachine.support.DefaultStateMachineExecutor@13e24b22
2024-05-27 22:58:14.209 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : started WAIT_RECEIVE WAIT_DELIVER FINISH WAIT_PAYMENT / WAIT_PAYMENT / uuid=7a254cb7-5a92-4f0b-b6c7-3edc4d9e2de2 / id=null
pay,feedback by statemachine:{order=Order(orderId=1, orderStatus=WAIT_DELIVER), id=fc2c0720-e6ba-9bf8-d359-72a6c61b4186, timestamp=1716821894196}try to deliver,order no:1
deliver,feedback by statemachine:{order=Order(orderId=1, orderStatus=WAIT_RECEIVE), id=e743d376-22e1-bfc3-1c62-7131ff1bf7c1, timestamp=1716821894227}try to receiver,order no:1
receive,feedback by statemachine:{order=Order(orderId=1, orderStatus=FINISH), id=652167b8-e74f-bde2-62f7-94bdbb5bad7e, timestamp=1716821894229}
2024-05-27 22:58:14.230 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@13e24b22
2024-05-27 22:58:14.230 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : stopped WAIT_RECEIVE WAIT_DELIVER FINISH WAIT_PAYMENT / / uuid=7a254cb7-5a92-4f0b-b6c7-3edc4d9e2de2 / id=null
try to pay,order no:2
2024-05-27 22:58:14.231 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : started org.springframework.statemachine.support.DefaultStateMachineExecutor@13e24b22
2024-05-27 22:58:14.231 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : started WAIT_RECEIVE WAIT_DELIVER FINISH WAIT_PAYMENT / WAIT_PAYMENT / uuid=7a254cb7-5a92-4f0b-b6c7-3edc4d9e2de2 / id=null
pay,feedback by statemachine:{order=Order(orderId=2, orderStatus=WAIT_DELIVER), id=d331fa76-8a28-aaa7-6257-a9404c2084d6, timestamp=1716821894230}try to deliver,order no:2
deliver,feedback by statemachine:{order=Order(orderId=2, orderStatus=WAIT_RECEIVE), id=4e930443-6b04-fd86-6740-5631db2aea1d, timestamp=1716821894232}try to receiver,order no:2
receive,feedback by statemachine:{order=Order(orderId=2, orderStatus=FINISH), id=6473cc9e-5cd9-0de5-12c8-7d51dd3f9da6, timestamp=1716821894233}
2024-05-27 22:58:14.234 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@13e24b22
2024-05-27 22:58:14.234 INFO 13306 --- [nio-8088-exec-2] o.s.s.support.LifecycleObjectSupport : stopped WAIT_RECEIVE WAIT_DELIVER FINISH WAIT_PAYMENT / / uuid=7a254cb7-5a92-4f0b-b6c7-3edc4d9e2de2 / id=null
all orders:{1=Order(orderId=1, orderStatus=FINISH), 2=Order(orderId=2, orderStatus=FINISH)}

4.引用

  • Spring State Machine
  • Spring Boot集成statemachine快速入門demo | Harries Blog?

? ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/19620.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/19620.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/19620.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【面試】什么是Java虛擬機

目錄 1. 說明2. 關鍵點 1. 說明 1.Java虛擬機&#xff08;Java Virtual Machine&#xff0c;簡稱JVM&#xff09;是運行所有Java程序的抽象計算機&#xff0c;是Java語言的運行環境。2.JVM是Java平臺無關性的關鍵&#xff0c;它允許Java程序在任何支持JVM的硬件和操作系統上運…

【大數據面試題】34 手寫一個 Flink SQL 樣例

一步一個腳印,一天一道大數據面試題 博主希望能夠得到大家的點贊收,藏支持!非常感謝~ 點贊,收藏是情分,不點是本分。祝你身體健康,事事順心! 我們來看看 Flink SQL大概流程和樣例: 流程: 1.創建 流處理環境 StreamExecutionEnvironment env 2.創建 表環境 StreamTab…

為啥裝了erlang,還報錯erl: command not found?

轉載說明&#xff1a;如果您喜歡這篇文章并打算轉載它&#xff0c;請私信作者取得授權。感謝您喜愛本文&#xff0c;請文明轉載&#xff0c;謝謝。 問題背景&#xff1a; 在一臺不通外網的服務器上裝rabbitmq&#xff0c;然后在啟動的時候&#xff0c;遇到了報錯 “/usr/lib/…

C#中使用Mapster

Mapster是一個開源的.NET對象映射庫&#xff0c;它提供了一種簡單而強大的方式來處理對象之間的映射。 多個映射框架的性能對比&#xff1a; 第一步安裝Mapster 使用方法 public class Test {public string name { get; set; }public string sex { get; set; }public string…

C語言數據結構(超詳細講解)| 二叉樹的實現

二叉樹 引言 在計算機科學中&#xff0c;數據結構是算法設計的基石&#xff0c;而二叉樹&#xff08;Binary Tree&#xff09;作為一種基礎且廣泛應用的數據結構&#xff0c;具有重要的地位。無論是在數據庫索引、內存管理&#xff0c;還是在編譯器實現中&#xff0c;二叉樹都…

記錄Win11安裝打印機驅動過程

1. 首先下載打印機對應型號的驅動 可以從這里下載&#xff1a;打印機驅動,打印機驅動下載 - 打印機驅動網 2. 下載 3. 打開控制面板-->設備和打印機 找到目標打印機添加設備即可 新增打印紙張尺寸

B站稿件生產平臺高可用建設分享

背景 B站作為國內領先的內容分享平臺&#xff0c;其核心功能之一便是支持UP主們創作并分享各類視頻內容。UP主稿件系統作為B站內容生產的關鍵環節&#xff0c;承擔著從內容創作到發布的全過程管理。為了滿足不同創作者的需求&#xff0c;B站提供了多種投稿渠道&#xff0c;包括…

方差分析的七種類型

方差分析&#xff08;ANOVA&#xff09;是一種用于檢驗兩個以上樣本均數差別的顯著性統計方法。根據不同的研究設計和數據類型&#xff0c;方差分析可以分為以下7種類型。 一、單因素方差分析 ①單因素方差分析說明 單因素方差分析用于研究一個定類數據&#xff08;自變量&am…

【原創教程】MES服務器與成品打標機控制說明

1 實現的功能及應用的場合 MES即制造執行系統(manufacturing execution system,簡稱MES),即在加強MRP計劃的執行功能,把MRP計劃同車間作業現場控制,通過執行系統聯系起來。 MES是一個生產管理智能化的一個系統,是用于生產時記錄數據、產量等信息的智能管理系統。 該項…

SpockMockStatic方法

SpockMockStatic方法 參考: https://blog.csdn.net/knighttools/article/details/44630975 ? static方法 import com.meituan.mafka.client.producer.IProducerProcessor; import com.meituan.mdp.langmodel.api.message.AssistantMessage; import com.sankuai.gaigc.arrang…

文件批量重命名001到100如何操作?這幾個文件改名小技巧學起來

文件批量重命名001到100怎么操作&#xff1f;作為打工一族&#xff0c;每天都需要跟很多文件打交道&#xff0c;有時文件太多了&#xff0c;查找起來像是大海撈針&#xff0c;特別是圖片文件。這個時候我們就需要對大量文件進行整理和排序&#xff0c;這樣有助于提高我們的工作…

微信小程序 自定義 tabBar

自定義 tabBar | 微信開放文檔 本文案例使用的Taro 非原生微信小程序 使用流程 1. 配置信息 在 app.json 中的 tabBar 項指定 custom 字段&#xff0c;同時其余 tabBar 相關配置也補充完整。所有 tab 頁的 json 里需聲明 usingComponents 項&#xff0c;也可以在 app.json 全局…

Java語言的應用場景

1、開發移動應用程序 例如&#xff1a;Android。 2、開發服務應用程序&#xff0c;搭建WEB界面。 例如&#xff1a;Servlet、JSP。 3、開發應用服務器。 例如Tomcat。 4、開發網絡通信程序。 5、開發圖形化界面桌面端。 Java支持用AWT、Swing、JavaFX三種包來開發圖形化界面…

電腦提示缺少vcruntime140_1.dll的解決方法,總結7種有效方法

vcruntime140_1.dll是Microsoft Visual C 2015運行時庫的一部分&#xff0c;它為使用Visual Studio 2015開發的應用程序提供了必要的運行時組件。該文件支持C程序的執行&#xff0c;包括內存管理、輸入輸出操作以及多線程功能等。缺失或損壞此文件可能導致應用程序無法啟動或運…

廣告聯盟四大家

國內四大廣告承接商&#xff1a;①抖音旗下-穿山甲②快手旗下-快手聯盟③百度旗下-百青藤④騰訊旗下-優量匯 我們目前在互聯網上能看到的所有廣告都是由他們發放的&#xff0c;在其中我們打小游戲復活看廣告&#xff0c;獲得道具看廣告&#xff0c;看劇看廣告&#xff0c;這…

數據庫的隔離級別和索引使用

先看一下隔離級別&#xff0c; 隔離級別首先要明確 &#xff0c;隔離的越重&#xff0c;那么自然會失去效率&#xff0c;為什么有這么多的隔離級別&#xff0c;其實就是平衡業務關系盡可能的提高效率。 下面看下隔離級別和介紹&#xff1a; 讀未提交是指&#xff1a;一個事務…

Oracle SQL詳解

Oracle SQL是一種用于管理和操作Oracle數據庫的編程語言。以下是一些基本的Oracle SQL語法和建表建用戶的詳解。 創建用戶 在Oracle中&#xff0c;創建用戶通常需要具有足夠權限的用戶&#xff08;通常是具有DBA角色的用戶&#xff09;。以下是一個創建用戶的例子&#xff1a;…

基于詞頻統計的聚類算法(kmeans)

基于詞頻統計的聚類算法&#xff08;kmeans&#xff09; 數據集是三個政府報告文件&#xff0c;這里就不做詳細描述了&#xff0c;就是簡單的txt文件。 實驗過程主要分為如下幾步&#xff1a; 1.讀取數據并進行停用詞過濾 2.統計詞頻 3.基于三篇文章詞頻統計的層次聚類 4.基于…

廢品回收小程序怎么做?有哪些核心功能?

廢品回收行業正逐步走向高質量發展的道路。在國家政策的推動下&#xff0c;再生資源市場需求旺盛&#xff0c;行業內部競爭格局逐漸明朗。 隨著互聯網技術的發展&#xff0c;"互聯網回收"成為廢品回收行業的一個新趨勢。通過微信小程序這種線上平臺&#xff0c;用戶…

數據可視化在智慧園區中的核心價值解析

數據可視化在智慧園區中發揮著至關重要的價值。智慧園區是一種基于物聯網、大數據、云計算等先進技術的現代化管理模式&#xff0c;旨在通過智能化手段提升園區的管理效率、服務水平和用戶體驗。而數據可視化作為數據處理和展示的重要工具&#xff0c;正是智慧園區實現這些目標…