SpringBoot中集成eclipse.paho.client.mqttv3實現mqtt客戶端并支持斷線重連、線程池高并發改造、存儲入庫mqsql和redis示例業務流程,附資源下載

場景

SpringBoot整合MQTT服務器實現消息的發送與訂閱(推送消息與接收推送):

SpringBoot整合MQTT服務器實現消息的發送與訂閱(推送消息與接收推送)_服務端接收mqtt消息-CSDN博客

上面SpringBoot集成MQTT使用的是spring-integration-mqtt依賴,也是經常使用的方式。

其底層也是有對org.eclipse.paho.client.mqttv3的封裝和引用。

下面直接對org.eclipse.paho.client.mqttv3進行集成和簡單的業務示例梳理。

系統中需要對接第三方的硬件比如攝像頭報警系統,觸發報警時會通過mqtt協議發送json格式的報警數據。

項目啟動后需要連接配置的mqtt的broker的地址,并訂閱指定主題,當收到mqtt消息時進行解析并存儲進mysql和redis中。

Mqtt的Broker的搭建使用如下方式:

Windows上Mqtt的Broker/服務端的搭建-使用mosquitto:

Windows上Mqtt的Broker/服務端的搭建-使用mosquitto-CSDN博客

注:

博客:
霸道流氓氣質-CSDN博客

實現

新建SpringBoot項目并添加項目依賴

mqtt所需的依賴

??????? <!-- mqtt --><dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.4</version></dependency>

線程池使用guava依賴

??????? <!-- guava --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.2-jre</version><scope>provided</scope></dependency>

當然也可使用Java自帶的依賴,關于guava的使用參考如下

Java工具庫Guava并發相關工具類的使用示例:

Java工具庫Guava并發相關工具類的使用示例_moreexecutors.listeningdecorator-CSDN博客

Json解析相關的依賴

??????? <!-- 阿里JSON解析器 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version></dependency>

Lombok工具集依賴

??????? <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

其它連接mysql、mybatis、redis的依賴省略,見文末示例代碼。

yml文件添加mqtt配置

application.yml文件中添加mqtt連接相關的ip、端口、用戶名、密碼等需要配置的信息。

#mqtt數據配置
badao-mqtt:host: 127.0.0.1port: 1883user: adminpassword: 123456

然后新建配置類,用于獲取yml中配置的內容

package com.badao.demo.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** Class Name: mqttConfig* Description: 類功能說明*/
@Component("MqttConfig")
@ConfigurationProperties(prefix = "badao-mqtt")
public class MqttConfig {/*** mqqt地址*/private static String host;/*** mqtt端口*/private static String port;/*** mqtt用戶*/private static String user;/*** mqtt密碼*/private? static String password;public String getHost() {return host;}public void setHost(String host) {MqttConfig.host = host;}public String getPort() {return port;}public void setPort(String port) {MqttConfig.port = port;}public String getUser() {return user;}public void setUser(String user) {MqttConfig.user = user;}public String getPassword() {return password;}public void setPassword(String password) {MqttConfig.password = password;}
}

注意這里注解的prefix要與yml中的前綴一致。

這里@Component("MqttConfig")注解指定了名稱,后面使用。

MQTT相關連接、回調方法實現

完整項目目錄參考如下,新建三個mqtt相關的三個類

第一個類MqttReceiver,用來連接代理服務器,訂閱主題

package com.badao.demo.mqtt;import com.badao.demo.config.MqttConfig;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.websocket.ClientEndpoint;
import java.util.Random;/*** @ClassName: MqttReceiver* @Description: mqtt連接代理服務器,訂閱主題*/
@Component
@ClientEndpoint
@DependsOn("MqttConfig")
public class MqttReceiver {// mqtt配置public? String host;public? String port;public? String user;public? String password;public static MqttClient client;public static MqttService videoMqttService;public static String clientId = "badao_" + new Random().nextInt(999999999);public void start() {try {// broker為代理端,clientId即的客戶端id,MemoryPersistence設置clientId的保存形式,默認為以內存保存String broker = "tcp://"+this.host+":"+this.port;client = new MqttClient(broker, clientId, new MemoryPersistence());videoMqttService = new MqttService();// MQTT連接設置MqttConnectOptions connOpts = new MqttConnectOptions();// 修復過多發布bugconnOpts.setMaxInflight(1000);// 設置用戶名和密碼connOpts.setUserName(this.user);connOpts.setPassword(this.password.toCharArray());// 設置心跳時間間隔,服務端實時了解客戶端是否與其保持連接的情況connOpts.setKeepAliveInterval(5);connOpts.setMaxReconnectDelay(10);connOpts.setConnectionTimeout(10);connOpts.setAutomaticReconnect(true);// 設置是否清空session,這里如果設置為false表示服務器會保留客戶端的連接記錄,// 這里設置為true表示每次連接到服務器都以新的身份連接connOpts.setCleanSession(true);// 設置回調client.setCallback(new MqttMessageCallback());// 建立連接System.out.println("連接到mqtt服務器: " + broker);client.connect(connOpts);// 訂閱主題videoMqttService.subscribe(client);} catch (MqttException me) {me.printStackTrace();}}public void setHost(String host) {this.host = host;}public void setPort(String port) {this.port = port;}public void setUser(String user) {this.user = user;}public void setPassword(String password) {this.password = password;}/*** @Description: Spring實例化該Bean之后馬上執行此方法* @param:* @Return: void* @Exception:*/@PostConstructvoid init() {// 實例化mqtt對象MqttReceiver client = new MqttReceiver();// 從yml文件設置參數// 實例化mqtt配置對象MqttConfig mqttConfig =new MqttConfig();client.setHost(mqttConfig.getHost());client.setPort(mqttConfig.getPort());client.setUser(mqttConfig.getUser());client.setPassword(mqttConfig.getPassword());// 啟動client.start();}
}

第二個類MqttService用來配置接收到訂閱消息后,用來對消息的處理

package com.badao.demo.mqtt;import com.alibaba.fastjson.JSON;
import com.badao.demo.entity.TVideoMsg;
import com.badao.demo.entity.VideoAlarm;
import com.badao.demo.service.serviceImpl.TVideoMsgServiceImpl;
import com.badao.demo.utils.RedisCache;
import com.badao.demo.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import java.util.Date;/*** @ClassName: MqttService* @Description: mqtt訂閱消息處理*/
@Slf4j
public class MqttService {private final static String MQTT_VIDEO_TOPIC = "badao";private TVideoMsgServiceImpl tVideoMsgService= SpringUtils.getBean(TVideoMsgServiceImpl.class);private RedisCache redisCache= SpringUtils.getBean("redisCache");/*** @Description: mqtt接受到訂閱消息后,對消息的處理* @param: topic* @param: message* @Return: void* @Exception:*/public void getMqttMessage(String topic, MqttMessage message) {try {System.out.println("received topic:"+topic+",message:"+message.toString());if (MqttTopic.isMatched(MQTT_VIDEO_TOPIC, topic)) {String msg = new String(message.getPayload());//序列化json數據到實體VideoAlarm videoAlarm = JSON.parseObject(msg, VideoAlarm.class);//根據自己業務進行數據轉換為需要入庫的數據實體TVideoMsg tVideoMsgDTO= new TVideoMsg();tVideoMsgDTO.setTimestamp(videoAlarm.getTimestamp());tVideoMsgDTO.setAlgId(videoAlarm.getAlg_id());tVideoMsgDTO.setCameraId(videoAlarm.getCamera_id());tVideoMsgDTO.setImagePath(videoAlarm.getImage_path());tVideoMsgDTO.setAlarmDate(new Date());//mysql入庫存儲邏輯tVideoMsgService.insertTVideoMsg(tVideoMsgDTO);//redis緩存入庫邏輯String reKeyTemp="badaoTest:" + videoAlarm.getCamera_id();redisCache.setCacheObject(reKeyTemp,tVideoMsgDTO);}} catch (Exception e) {log.error(e.getMessage(), e);}}/*** @Description: 訂閱主題* @param: client* @Return: void* @Exception:*/public void subscribe(MqttClient client) {try {client.subscribe(MQTT_VIDEO_TOPIC);} catch (Exception e) {e.printStackTrace();}}
}

上面這個類為業務處理關鍵類,配置的主題為badao,然后這里需要在非Spring管理環境中獲取bean,比如需要獲取redis

private RedisCache redisCache= SpringUtils.getBean("redisCache");

以及獲取插入到mysql中的service

后面附SpringUtiles的具體實現以及service相關實現。

getMqttMessage用來對收到對應主題消息的處理,首先進行json序列化。

然后使用一個對應json字段的實體對象接收,后面模仿業務層面的處理,轉換為需要入庫的DTO,

分別進行存儲mysql數據庫和reids操作。

第三個類是MqttMessageCallback用來對建立連接、斷開連接、收到消息、自動重連的回調處理。

package com.badao.demo.mqtt;import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** @ClassName: MqttMessageCallback* @Description: mqtt回調函數*/
@Slf4j
public class MqttMessageCallback implements MqttCallbackExtended {public static MqttService videoMqttService;ExecutorService newFixedThreadPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),Runtime.getRuntime().availableProcessors(), 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(500), new ThreadFactoryBuilder().setNameFormat("mqtt-%d").build(), new ThreadPoolExecutor.AbortPolicy());/*** @Description: 服務器斷開與客戶機的連接時客戶機將調用此方法* @param: cause* @Return: void* @Exception:*/@Overridepublic void connectionLost(Throwable cause) {log.error("MQTT丟失連接");try {MqttReceiver.client.reconnect();} catch (MqttException e) {e.printStackTrace();}}/*** @Description: 當客戶機的與預訂主題相匹配的預訂到達時,就會調此方法* @param: topic* @param: message* @Return: void* @Exception:*/@Overridepublic void messageArrived(String topic, MqttMessage message) {videoMqttService = new MqttService();try {newFixedThreadPool.execute(() -> videoMqttService.getMqttMessage(topic, message));} catch (Exception e) {e.printStackTrace();}}/*** @Description: 由mqtt客戶機調用以將傳遞令牌傳回客戶機應用程序* @param: token* @Return: void* @Exception:*/@Overridepublic void deliveryComplete(IMqttDeliveryToken token) {}@Overridepublic void connectComplete(boolean b, String s) {log.error("MQTT觸發自動重連");try {videoMqttService = new MqttService();videoMqttService.subscribe(MqttReceiver.client);if (MqttReceiver.client.isConnected()) {log.error("MQTT重新連接成功!");} else {log.error("MQTT重連失敗!");}} catch (Exception e) {e.printStackTrace();}}
}

注意這里在收到消息的回調messageArrived中,使用線程池支持高并發的處理。

實現mqtt消息入庫、緩存相關的類

上面收到mqtt消息的處理中SpringUtils的代碼實現

package com.badao.demo.utils;import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;/*** spring工具類 方便在非spring管理環境中獲取bean**/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{/** Spring應用上下文環境 */private static ConfigurableListableBeanFactory beanFactory;@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException{SpringUtils.beanFactory = beanFactory;}/*** 獲取對象** @param name* @return Object 一個以所給名字注冊的bean的實例* @throws BeansException**/@SuppressWarnings("unchecked")public static <T> T getBean(String name) throws BeansException{return (T) beanFactory.getBean(name);}/*** 獲取類型為requiredType的對象** @param clz* @return* @throws BeansException**/public static <T> T getBean(Class<T> clz) throws BeansException{T result = (T) beanFactory.getBean(clz);return result;}/*** 如果BeanFactory包含一個與所給名稱匹配的bean定義,則返回true** @param name* @return boolean*/public static boolean containsBean(String name){return beanFactory.containsBean(name);}/*** 判斷以給定名字注冊的bean定義是一個singleton還是一個prototype。 如果與給定名字相應的bean定義沒有被找到,將會拋出一個異常(NoSuchBeanDefinitionException)** @param name* @return boolean* @throws NoSuchBeanDefinitionException**/public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException{return beanFactory.isSingleton(name);}/*** @param name* @return Class 注冊對象的類型* @throws NoSuchBeanDefinitionException**/public static Class<?> getType(String name) throws NoSuchBeanDefinitionException{return beanFactory.getType(name);}/*** 如果給定的bean名字在bean定義中有別名,則返回這些別名** @param name* @return* @throws NoSuchBeanDefinitionException**/public static String[] getAliases(String name) throws NoSuchBeanDefinitionException{return beanFactory.getAliases(name);}/*** 獲取aop代理對象** @param invoker* @return*/@SuppressWarnings("unchecked")public static <T> T getAopProxy(T invoker){return (T) AopContext.currentProxy();}
}

首先建立一個mysql的表

然后上面收到mqtt消息對應的實體類TVideoMsg

package com.badao.demo.entity;
import java.util.Date;public class TVideoMsg
{private static final long serialVersionUID = 1L;private Long id;private Long timestamp;private Long algId;private Long cameraId;private String algName;private String confirm;private String path;private String imagePath;private String alarmRule;private String status;private String handlePeople;private Date handleDate;private Date alarmDate;private String handleContent;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public Long getTimestamp() {return timestamp;}public void setTimestamp(Long timestamp) {this.timestamp = timestamp;}public Long getAlgId() {return algId;}public void setAlgId(Long algId) {this.algId = algId;}public Long getCameraId() {return cameraId;}public void setCameraId(Long cameraId) {this.cameraId = cameraId;}public String getAlgName() {return algName;}public void setAlgName(String algName) {this.algName = algName;}public String getConfirm() {return confirm;}public void setConfirm(String confirm) {this.confirm = confirm;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String getImagePath() {return imagePath;}public void setImagePath(String imagePath) {this.imagePath = imagePath;}public String getAlarmRule() {return alarmRule;}public void setAlarmRule(String alarmRule) {this.alarmRule = alarmRule;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public String getHandlePeople() {return handlePeople;}public void setHandlePeople(String handlePeople) {this.handlePeople = handlePeople;}public Date getHandleDate() {return handleDate;}public void setHandleDate(Date handleDate) {this.handleDate = handleDate;}public Date getAlarmDate() {return alarmDate;}public void setAlarmDate(Date alarmDate) {this.alarmDate = alarmDate;}public String getHandleContent() {return handleContent;}public void setHandleContent(String handleContent) {this.handleContent = handleContent;}
}

消息數據轉換后的DTO類VideoAlarm

import lombok.Data;@Data
public class VideoAlarm {private Long id;private Long timestamp;private Long alg_id;private Long camera_id;private String alg_name;private Integer confirm;private String path;private String image_path;private String alarm_rule;private boolean status = false;}

其它mapper層、service層代碼等可自行根據表使用代碼生成工具等生成。

測試mqtt連接、斷線重連、接受json數據解析入庫存儲流程

啟動并連接mqtt服務端

測試斷連重連

入庫存儲測試

全部代碼資源、mosquitto、sql文件資源打包下載

下載地址:

https://download.csdn.net/download/BADAO_LIUMANG_QIZHI/90283310

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

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

相關文章

【考研408數據結構-08】 圖論基礎:存儲結構與遍歷算法

&#x1f4da; 【考研408數據結構-08】 圖論基礎&#xff1a;存儲結構與遍歷算法 &#x1f3af; 考頻&#xff1a;????? | 題型&#xff1a;選擇題、綜合應用題、算法設計題 | 分值&#xff1a;約8-15分 引言 想象你正在規劃一次跨省自駕游&#xff0c;面前攤開一張復雜的…

SQL查詢語句的執行順序

好的&#xff0c;我們來詳細講解一下 SQL 查詢語句的執行順序。 很多人會誤以為 SQL 的執行順序就是我們寫的順序&#xff08;SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY&#xff09;&#xff0c;但實際上&#xff0c;數據庫引擎在底層處理查詢…

【Android】OKHttp網絡請求原理和弱網優化

【Android】OKHttp網絡請求原理和弱網優化 1. OkHttp 網絡請求原理 OkHttp 的請求過程可以分為 四個關鍵階段&#xff1a; &#xff08;假設你是通過 OkHttpClient.newCall(request).enqueue(callback) 發的請求&#xff09; OkHttpClient│▼ Dispatcher (調度器)│▼ RealC…

概率論基礎教程第4章 隨機變量(四)

4.7 泊松隨機變量 定義 泊松隨機變量&#xff1a;如果一個取值于 $ 0, 1, 2, \ldots $ 的隨機變量對某一個 $ \lambda > 0 $&#xff0c;其分布列為&#xff1a; p(i)P{Xi}e?λλii!i0,1,2,?(7.1) \boxed{p(i) P\{X i\} e^{-\lambda} \frac{\lambda^i}{i!} \qquad i 0…

Unity高級開發:反射原理深入解析與實踐指南 C#

Unity高級開發&#xff1a;反射原理深入解析與實踐指南 在Unity游戲開發中&#xff0c;反射&#xff08;Reflection&#xff09; 是一項強大的元編程技術&#xff0c;它允許程序在運行時動態地獲取類型信息、創建對象和調用方法。根據Unity官方統計&#xff0c;超過78%的商業游…

任務五 推薦頁面功能開發

一、推薦頁面需求分析 由推薦頁面效果圖,可以看出,推薦頁面主要由頂部輪播圖和歌單列表頁面組成 二、推薦頁面輪播圖組件封裝 由于輪播圖,可能在項目多個地方用到,因此可以將輪播圖抽調成一個組件,然后各個頁面調用這個組件。 在開發輪播圖組件時,需要安裝better-scro…

【工具使用-Docker容器】構建自己的鏡像和容器

1. 鏡像和容器介紹 鏡像&#xff08;Image&#xff09;是一個只讀的模板&#xff0c;包含了運行某個應用所需的全部內容&#xff0c;比如&#xff1a; 操作系統&#xff08;比如 Ubuntu&#xff09;應用程序代碼運行環境&#xff08;如 Python、Java、Node.js 等&#xff09;庫…

Apache Shiro550 漏洞(CVE-2016-4437):原理剖析與實戰 SOP

在 Web 安全領域&#xff0c;反序列化漏洞一直是威脅等級極高的存在&#xff0c;而 Apache Shiro 框架中的 Shiro550 漏洞&#xff08;CVE-2016-4437&#xff09;&#xff0c;更是因利用門檻低、影響范圍廣&#xff0c;成為滲透測試中頻繁遇到的經典漏洞。本文將從 “原理拆解”…

安卓開發者自學鴻蒙開發3持久化/數據與UI綁定

AppStorage,PersistentStorage與StorageLink AppStorage是應用全局狀態管理器,數據存儲于內存中,常見的如全局的黑暗模式,StorageLink是用來綁定AppStorage的鍵到ui上的工具,省去了用戶手寫代碼的無聊過程,PersistentStorage可以綁定AppStorage的鍵,自動持久化到磁盤,同時支持多…

GitHub宕機生存指南:從應急協作到高可用架構設計

GitHub宕機生存指南&#xff1a;從應急協作到高可用架構設計 摘要&#xff1a; GitHub作為全球開發者的協作中心&#xff0c;其服務穩定性至關重要。然而&#xff0c;任何在線服務都無法保證100%的可用性。本文深入探討了當GitHub意外宕機時&#xff0c;開發團隊應如何應對。我…

機器學習算法篇(十三)------詞向量轉化的算法思想詳解與基于詞向量轉換的文本數據處理的好評差評分類實戰(NPL基礎實戰)

目錄 一、詞向量原理介紹 (1). 詞向量的核心概念 (2). 傳統文本表示的局限性 1. 獨熱編碼&#xff08;One-Hot Encoding&#xff09; 2. 詞袋模型&#xff08;Bag of Words&#xff09; 3. TF-IDF (3). 詞向量的核心原理 (4). 主流詞向量模型 1. Word2Vec&#xff08;20…

JS自定義函數(2)

1. 變量的作用域全局變量定義&#xff1a;在函數外聲明的變量作用范圍&#xff1a;在整個JS文檔中生效生命周期&#xff1a;頁面關閉時銷毀局部變量定義&#xff1a;在函數內用 var 聲明的變量作用范圍&#xff1a;只能在函數內部使用生命周期&#xff1a;函數執行完畢時銷毀作…

【數據集】Argoverse 數據集:自動駕駛研究的強大基石

Argoverse數據集&#xff1a;自動駕駛研究的強大基石 在自動駕駛技術蓬勃發展的當下&#xff0c;高質量的數據集對于推動相關算法研究和模型訓練起著舉足輕重的作用。Argoverse 數據集便是其中的佼佼者&#xff0c;它為自動駕駛領域的眾多任務提供了豐富且優質的數據資源。 一、…

--- 哈希表和哈希沖突 ---

哈希&#xff08;散列&#xff09;方法是對插入的數據通過哈希函數計算出一個哈希地值&#xff0c;并將這個哈希地址作為儲存改數據的地址&#xff0c;這樣下次再查找這個數據時&#xff0c;只需要通過哈希函數再獲取到該地址然后直接去拿就好這樣就做到了不經過任何比較&#…

數學建模-評價類問題-優劣解距離法(TOPSIS)

1-AI帶你認識TOPSIS&#x1f4d8; 一、TOPSIS 方法簡介1. ??基本定義&#xff1a;????TOPSIS&#xff08;Technique for Order Preference by Similarity to an Ideal Solution&#xff09;??&#xff0c;中文通常稱為&#xff1a;???優劣解距離法?????逼近理想…

Go協程:從匯編視角揭秘實現奧秘

&#x1f680; Go協程&#xff1a;從匯編視角揭秘實現奧秘 #Go語言 #協程原理 #并發編程 #底層實現 引用&#xff1a; 關于 Go 協同程序&#xff08;Coroutines 協程&#xff09;、Go 匯編及一些注意事項。 &#x1f31f; 前言&#xff1a;重新定義并發編程范式 在當今高并發…

MySQL 事務(重點)

MySQL 這個東西注定是可能會被多個用戶/客戶端來同時訪問的&#xff0c;這是肯定的&#xff0c;MySQL 中存放的都是數據&#xff0c;數據可能有一個上層線程在用&#xff0c;也有可能另一個線程也要用...數據是被所有人共享的&#xff0c;所以就注定了 MySQL 這樣的服務在一個時…

uniapp:h5鏈接拉起支付寶支付

場景&#xff1a;APP內點擊支付寶支付&#xff0c;后臺返回類似鏈接https://qr.alipay.com/bax***********c3050 通常做法是&#xff0c;使用plus.runtime.openURL(deeplink);先打開瀏覽器&#xff0c;瀏覽器會提示打開支付寶&#xff0c;之后是支付流程。現在可以省略跳轉h5的…

吳恩達 Machine Learning(Class 3)

Week 11.1 K-means Cluster centroidK-means 是無監督學習中聚類算法的一種&#xff0c;核心在于更新聚類質心&#xff1b;首先將每個點分配給幾個聚類質心&#xff0c;取決于那些點離哪個質心更近&#xff1b;然后將幾個聚類質心移動到分配給他的所有點的平均值&#xff0c;不…

MyBatis 動態查詢語句詳解:讓 SQL 更靈活可控

MyBatis 動態查詢語句詳解&#xff1a;讓 SQL 更靈活可控 在日常的數據庫操作中&#xff0c;我們經常會遇到需要根據不同條件拼接 SQL 語句的場景。比如查詢用戶時&#xff0c;可能需要根據姓名、年齡、性別等多個條件進行篩選&#xff0c;而這些條件往往是動態變化的 —— 有時…