当前位置: 首页 > news >正文

Saga分布式事务框架执行逻辑

Saga分布式事务框架执行逻辑

📋 目录

  • 框架概述
  • 核心组件架构
  • 数据库表设计
  • 完整执行流程
  • 节点发现与调用机制
  • 精简补偿策略设计
  • 总结

框架概述

这是一个基于数据库驱动的Saga分布式事务框架,专门用于解决跨服务间数据同步的一致性问题。框架采用了混合编排模式,结合了集中式任务分解和分布式执行的优势。

核心设计理念

  • 🎯 分层解耦: 任务分解与任务执行完全分离
  • 🌐 节点自治: 消费端节点独立执行和管理任务
  • 📊 状态透明: 完整的执行日志和状态追踪
  • 🔄 容错恢复: 失败重试与自动补偿机制
  • ⚖️ 负载均衡: 基于节点负载的智能调度

业务场景

  • 空间同步开启: 跨服务复制空间、页面、权限等数据
  • 增量数据同步: 已开启同步的项目进行增量更新
  • 同步关闭清理: 关闭同步时清理相关数据

核心组件架构

``mermaid

graph TBsubgraph "业务触发层"A1[空间同步开启] --> B1[业务端拆解步骤]A2[增量数据更新] --> B1A3[同步关闭清理] --> B1endsubgraph "任务分解层"B1 --> C1[存储distribute_event]C1 --> C2[存储distribute_event_step]C2 --> C3[HTTP发送步骤数据]endsubgraph "消费端接收层"C3 --> D1[消费端接收HTTP请求]D1 --> D2[存储distribute_event_step_log]D2 --> D3[返回接收确认]D3 --> D4[业务端更新状态为待消费]endsubgraph "定时执行层"D4 --> E1[定时任务扫描待执行记录]E1 --> E2[2线程并发控制]E2 --> E3[执行具体业务逻辑]E3 --> E4[HTTP回调通知结果]E4 --> E5[业务端更新状态]end

数据库表设计

📋 核心表结构

1. distribute_event (主事务表)

记录顶层业务事务的基本信息和整体状态。

2. distribute_event_step (步骤表)

记录事务分解后的各个原子步骤信息。

3. distribute_event_step_log (执行日志表) ✨ 完整设计

记录消费端节点的执行日志,实现简洁而强大的幂等性保证、重试机制和通知状态管理。

CREATE TABLE distribute_event_step_log (id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',step_code VARCHAR(64) NOT NULL COMMENT '关联业务端distribute_event_step.code',job_code VARCHAR(64) NOT NULL COMMENT '主事务编码,关联业务端distribute_event.code',consumer_node VARCHAR(50) NOT NULL COMMENT '消费者节点地址',-- 幂等性保证字段execution_key VARCHAR(128) NOT NULL COMMENT '执行唯一键: {step_code}_{consumer_node}_{yyyyMMdd}',business_key VARCHAR(64) COMMENT '业务唯一键,基于业务数据哈希值',-- 执行状态管理exec_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '执行状态: PENDING, EXECUTING, SUCCESS, FAILED, RETRYING',retry_count INT DEFAULT 0 COMMENT '当前重试次数',max_retry INT DEFAULT 3 COMMENT '最大重试次数',-- 通知状态管理(新增)notify_status VARCHAR(20) DEFAULT 'NOT_REQUIRED' COMMENT '通知状态: NOT_REQUIRED, PENDING, SUCCESS, FAILED',notify_retry_count INT DEFAULT 0 COMMENT '通知重试次数',max_notify_retry INT DEFAULT 3 COMMENT '最大通知重试次数',next_notify_time TIMESTAMP NULL COMMENT '下次通知时间',notify_url VARCHAR(255) COMMENT '通知回调地址',-- 执行信息payload TEXT COMMENT '执行数据载荷',result_data TEXT COMMENT '执行结果数据',error_message TEXT COMMENT '执行错误信息',notify_error_message TEXT COMMENT '通知错误信息',start_time TIMESTAMP NULL COMMENT '开始执行时间',end_time TIMESTAMP NULL COMMENT '结束执行时间',next_retry_time TIMESTAMP NULL COMMENT '下次执行重试时间',-- 回滚支持rollback_data TEXT COMMENT '回滚数据快照,JSON格式',is_rollback TINYINT(1) DEFAULT 0 COMMENT '是否已回滚',create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',-- 幂等性保证索引UNIQUE KEY uk_execution_key (execution_key),UNIQUE KEY uk_business_key (step_code, business_key),-- 查询优化索引INDEX idx_exec_status (exec_status),INDEX idx_notify_status (notify_status, next_notify_time),INDEX idx_step_code (step_code),INDEX idx_consumer_node (consumer_node),INDEX idx_retry_time (next_retry_time),INDEX idx_job_code (job_code)
);

📊 字段设计详解与使用说明

1. 幂等性保证字段

/*** execution_key: 执行唯一键* 用途: 防止同一步骤在同一节点同一天重复执行* 格式: SPACE_SYNC_001_192.168.1.10:8080_20240316* 使用场景: 消费端接收HTTP请求时检查是否已存在相同的execution_key*/
public String generateExecutionKey(String stepCode, String consumerNode) {String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));return String.format("%s_%s_%s", stepCode, consumerNode, dateStr);
}/*** business_key: 业务唯一键* 用途: 基于业务数据内容的去重,防止相同业务数据重复处理* 生成: 对payload业务数据进行MD5哈希* 使用场景: 当业务数据完全相同时避免重复执行*/
public String generateBusinessKey(Object payload) {String payloadJson = JSON.toJSONString(payload);return DigestUtils.md5DigestAsHex(payloadJson.getBytes()).substring(0, 8);
}

2. 状态管理字段

/*** exec_status: 执行状态* PENDING: 待执行 - 刚接收到任务,等待定时器扫描* EXECUTING: 执行中 - 正在执行业务逻辑* SUCCESS: 执行成功 - 业务逻辑执行完成* FAILED: 执行失败 - 重试次数耗尽后的最终失败状态* RETRYING: 重试中 - 执行失败后等待重试的状态*//*** notify_status: 通知状态* NOT_REQUIRED: 无需通知 - 执行中或失败时的默认状态* PENDING: 待通知 - 执行成功后需要通知业务端* SUCCESS: 通知成功 - 业务端已收到通知并确认* FAILED: 通知失败 - 通知重试次数耗尽后的状态*/

3. 重试机制字段

/*** retry_count / max_retry: 执行重试控制* 用途: 控制业务逻辑执行的重试次数,避免无限重试* 逻辑: 失败时retry_count+1,超过max_retry则标记为FAILED*//*** notify_retry_count / max_notify_retry: 通知重试控制* 用途: 控制通知业务端的重试次数,确保通知到位* 逻辑: 通知失败时notify_retry_count+1,采用指数退避策略*//*** next_retry_time / next_notify_time: 重试时间控制* 用途: 指数退避算法的时间调度* 计算: delay = Math.pow(2, retryCount) * baseDelaySeconds*/

4. 数据存储字段

/*** payload: 执行数据载荷* 用途: 存储从业务端接收的步骤执行数据* 格式: JSON字符串,包含业务逻辑执行所需的所有参数*//*** result_data: 执行结果数据* 用途: 存储业务逻辑执行后的结果,用于通知业务端* 格式: JSON字符串,包含执行结果、影响的数据ID等*//*** rollback_data: 回滚数据快照* 用途: 存储执行前的原始数据状态,用于失败回滚* 格式: JSON字符串,包含需要删除的数据ID列表等*/

完整执行流程

🎆 整体流程时序图(数据库分离)

sequenceDiagramparticipant BIZ as 业务服务Aparticipant BIZ_DB as 业务端数据库participant BIZ2 as 业务服务B(消费端)participant CONSUMER_DB as 消费端数据库participant TASK as 定时任务Note over BIZ,TASK: 阶段一: 业务触发与任务分解BIZ->>BIZ: 1. 业务触发(空间同步/增量更新等)BIZ->>BIZ: 2. 执行步骤拆解逻辑BIZ->>BIZ_DB: 3. 存储主事务 distribute_eventBIZ->>BIZ_DB: 4. 存储子步骤 distribute_event_stepNote over BIZ,TASK: 阶段二: HTTP任务分发BIZ->>BIZ2: 5. HTTP请求发送步骤数据BIZ2->>CONSUMER_DB: 6. 存储执行日志 distribute_event_step_logBIZ2->>BIZ: 7. 返回接收确认BIZ->>BIZ_DB: 8. 更新步骤状态为'待消费'Note over BIZ,TASK: 阶段三: 定时消费执行(限流2线程)TASK->>CONSUMER_DB: 9. 扫描待执行状态记录TASK->>TASK: 10. 并发控制(最多2线程)TASK->>CONSUMER_DB: 11. 更新exec_status为'EXECUTING'TASK->>TASK: 12. 执行具体业务逻辑alt 执行成功TASK->>CONSUMER_DB: 13a. 更新exec_status为'SUCCESS'TASK->>CONSUMER_DB: 14a. 设置notify_status为'PENDING'Note over BIZ,TASK: 阶段四: 通知业务端(指数退避重试)TASK->>BIZ: 15a. HTTP回调通知执行结果alt 通知成功BIZ->>TASK: 16a. 返回200状态TASK->>CONSUMER_DB: 17a. 更新notify_status为'SUCCESS'BIZ->>BIZ_DB: 18a. 更新distribute_event_step状态BIZ->>BIZ_DB: 19a. 更新distribute_event主事务状态else 通知失败BIZ->>TASK: 16b. 返回非200状态或网络异常TASK->>CONSUMER_DB: 17b. notify_retry_count+1alt 通知重试次数 < 3TASK->>CONSUMER_DB: 18b. 计算next_notify_time(指数退避)Note right of TASK: 等待指数退避时间后重新通知TASK->>BIZ: 19b. 重新发送通知(循环至16a)else 通知重试次数 >= 3TASK->>CONSUMER_DB: 20b. 更新notify_status为'FAILED'Note right of TASK: 通知失败,需人工介入endendelse 执行失败TASK->>CONSUMER_DB: 13c. 更新retry_count+1alt 执行重试次数 < 3TASK->>CONSUMER_DB: 14c. 更新exec_status为'RETRYING'TASK->>CONSUMER_DB: 15c. 删除当前记录TASK->>CONSUMER_DB: 16c. 重新插入新记录(计算next_retry_time)Note right of TASK: 等待指数退避时间后重新执行else 执行重试次数 >= 3TASK->>CONSUMER_DB: 17c. 更新exec_status为'FAILED'TASK->>BIZ: 18c. 通知执行最终失败BIZ->>BIZ: 19c. 触发回滚逻辑(删除重新开始)endend

整体执行流程图

flowchart TDA[业务触发] --> B[拆解步骤存储]B --> C[HTTP发送步骤数据]C --> D[消费端存储日志]D --> E[更新状态为待消费]E --> F[定时任务扫描]F --> G[2线程并发执行]G --> H{执行结果}H -->|成功| I[HTTP回调通知]H -->|失败| J{重试次数}J -->|<3次| K[指数退避重试]J -->|>=3次| L[触发回滚删除]I --> M[更新主事务状态]L --> N[通知失败完成]

节点发现与调用机制

服务节点通过心跳注册,基于负载权重选择最优节点执行任务。

@Service
public class DistributeNodeRegistry {@Scheduled(fixedRate = 30000) // 每30秒心跳public void heartbeat() {String nodeAddress = getLocalNodeAddress();NodeMetadata metadata = collectNodeMetadata(); // 收集CPU、内存、任务数量等nodeRegistryMapper.upsertNode(NodeRegistryRecord.builder().serviceName(getServiceName()).nodeAddress(nodeAddress).status(1) // 在线.lastHeartbeatTime(new Date()).metadata(JSON.toJSONString(metadata)).build());}// 选择最优节点(基于负载权重)public String selectOptimalNode(String serviceName) {List<NodeRegistryRecord> nodes = nodeRegistryMapper.selectAvailableNodes(serviceName);return nodes.stream().min(Comparator.comparing(this::calculateNodeLoad)).map(NodeRegistryRecord::getNodeAddress).orElseThrow(() -> new NoAvailableNodeException("无可用节点"));}
}

🔄 精简补偿策略设计

执行重试与通知重试机制

@Component
public class RetryAndNotificationService {/*** 处理执行失败 - 重试机制(删除重新插入)*/public void handleExecutionFailure(DistributeEventStepLog stepLog, String errorMessage) {int currentRetry = stepLog.getRetryCount();if (currentRetry < stepLog.getMaxRetry()) {// 还有重试机会 - 删除重新插入executeRetryByReinsert(stepLog, errorMessage);} else {// 重试次数耗尽,触发回滚triggerRollback(stepLog, errorMessage);}}/*** 执行重试逻辑:删除重新插入*/private void executeRetryByReinsert(DistributeEventStepLog stepLog, String errorMessage) {try {// 1. 更新状态为 RETRYINGstepLogMapper.updateStatus(stepLog.getId(), "RETRYING", errorMessage);// 2. 计算下次重试时间(指数退避)long delaySeconds = (long) Math.pow(2, stepLog.getRetryCount() + 1) * 30;Timestamp nextRetryTime = new Timestamp(System.currentTimeMillis() + delaySeconds * 1000);// 3. 删除当前记录stepLogMapper.deleteById(stepLog.getId());// 4. 重新插入新记录DistributeEventStepLog newStepLog = DistributeEventStepLog.builder().stepCode(stepLog.getStepCode()).jobCode(stepLog.getJobCode()).consumerNode(stepLog.getConsumerNode()).executionKey(stepLog.getExecutionKey()).businessKey(stepLog.getBusinessKey()).execStatus("PENDING").retryCount(stepLog.getRetryCount() + 1).maxRetry(stepLog.getMaxRetry()).nextRetryTime(nextRetryTime).payload(stepLog.getPayload()).rollbackData(stepLog.getRollbackData()).build();stepLogMapper.insert(newStepLog);log.info("执行重试安排成功,第{}次重试,下次执行时间: {}", newStepLog.getRetryCount(), nextRetryTime);} catch (Exception e) {log.error("执行重试安排失败: {}", stepLog.getStepCode(), e);}}/*** 处理通知失败 - 指数退避重试*/public void handleNotificationFailure(DistributeEventStepLog stepLog, String notifyErrorMessage) {int currentNotifyRetry = stepLog.getNotifyRetryCount();if (currentNotifyRetry < stepLog.getMaxNotifyRetry()) {// 还有通知重试机会 - 指数退避scheduleNotificationRetry(stepLog, notifyErrorMessage);} else {// 通知重试次数耗尽markNotificationFailed(stepLog, notifyErrorMessage);}}/*** 安排通知重试(指数退避)*/private void scheduleNotificationRetry(DistributeEventStepLog stepLog, String notifyErrorMessage) {try {int nextNotifyRetryCount = stepLog.getNotifyRetryCount() + 1;// 指数退避算法: 2^n * 60秒long delaySeconds = (long) Math.pow(2, nextNotifyRetryCount) * 60;Timestamp nextNotifyTime = new Timestamp(System.currentTimeMillis() + delaySeconds * 1000);stepLogMapper.updateNotificationForRetry(stepLog.getId(),nextNotifyRetryCount,nextNotifyTime,notifyErrorMessage);log.info("通知重试安排成功,第{}次重试,下次通知时间: {}", nextNotifyRetryCount, nextNotifyTime);} catch (Exception e) {log.error("通知重试安排失败: {}", stepLog.getStepCode(), e);}}/*** 回滚机制:删除重新开始*/private void triggerRollback(DistributeEventStepLog stepLog, String errorMessage) {try {// 1. 标记为执行失败stepLogMapper.updateStatus(stepLog.getId(), "FAILED", errorMessage);// 2. 执行回滚操作(删除相关数据)executeRollbackAction(stepLog);// 3. 标记回滚完成stepLogMapper.markAsRollback(stepLog.getId());// 4. 通知业务端失败notifyBusinessFailure(stepLog);} catch (Exception e) {log.error("回滚执行失败: {}", stepLog.getStepCode(), e);alertService.sendRollbackFailureAlert(stepLog, e);}}// 执行具体的回滚操作private void executeRollbackAction(DistributeEventStepLog stepLog) {String rollbackData = stepLog.getRollbackData();if (StringUtils.isBlank(rollbackData)) return;RollbackSnapshot snapshot = JSON.parseObject(rollbackData, RollbackSnapshot.class);switch (snapshot.getStepType()) {case "PAGE_CREATE":pageService.deleteById(snapshot.getEntityId());break;case "DATA_COPY":dataService.deleteBatch(snapshot.getDataIds());break;case "PERMISSION_GRANT":permissionService.revoke(snapshot.getPermissionIds());break;}}
}

总结

主要特点
流程清晰: 业务拆解 → HTTP分发 → 定时消费 → 状态同步
幂等性简单: 一天一次执行保证,避免重复处理
重试机制: 最多3次,指数退避,失败后智能回滚
回滚策略: 删除重新开始,简单有效
并发控制: 2线程限流,避免资源争抢
状态追踪: 完整的执行链路监控

核心优势
🎯 设计精简: 去除复杂的多重幂等性策略,采用基于日期的简单方案
💡 实用性强: 回滚即删除,符合业务实际需求
🔧 易于维护: 清晰的代码结构和执行流程
性能优化: 合理的并发控制和索引设计
🛡️ 可靠性高: 完善的重试和回滚机制

相关文章:

Saga分布式事务框架执行逻辑

Saga分布式事务框架执行逻辑 📋 目录框架概述 核心组件架构 数据库表设计 完整执行流程 节点发现与调用机制 精简补偿策略设计 总结框架概述 这是一个基于数据库驱动的Saga分布式事务框架,专门用于解决跨服务间数据同步的一致性问题。框架采用了混合编排模式,结合了集中式任…...

在Android开发中实现两个Intent跳转及数据交换的方法

在Android开发中,两个活动(Activity)之间的Intent跳转及数据交换是一项基本而重要的功能。这通常涉及两个步骤:从一个活动发送数据,并在另一个活动中接收数据。 一、发起活动 — 发送数据 首先是初始化一个Intent对象,并使用 putExtra()方法来传递数据。以下是具体的步骤…...

ARC188 做题记

训A () 题意 题解 \(\bf{record}\) B () 题意 题解 \(\bf{record}\) C () 题意 题解 \(\bf{record}\) D () 题意 题解 \(\bf{record}\) E () 题意 题解 \(\bf{record}\)...

AT_arc145_d [ARC145D] Non Arithmetic Progression Set

在这个构造题上展示出了战犯级表现。 首先你先别想和的限制,\(x - y \ne y - z\) 就已经是一个很强的限制了,先想想这个怎么做。 在我看来一个很无厘头的想法是,将 \(3\) 进制下分配数字,如果只有 \(0/1\) 必然合法,想想就会觉得很妙,但是很无厘头。 然后如何满足和的限制…...

Microsoft AI Genius | 第三集实战课正式开启:用 Copilot Studio 定制你的专属智能体

想为团队快速定制专业级 AI 智能体,却担心增加工程负担或陷入复杂流程? 我们在前两期已解锁 GitHub Copilot Agent Mode、Azure AI Foundry Agent Service(国际版)的开发秘籍,本期将带你直达智能体定制最前线——Microsoft AI Genius 2.0系列第三集实战课来了!请锁定9月2…...

C# 多线程编程核心要点:不只是Thread和lock

聊到C#多线程,很多人第一反应就是Thread和lock。没错,它们是基石,但如果你只停留在它们,那就像只会用菜刀切菜,永远做不出满汉全席。现代C#多线程的核心思想是 “高效地利用计算资源,并安全地处理并发”。下面我跟你捋几个最核心的点,保证接地气。1. 为什么要用多线程?…...

基于MATLAB的图像融合拼接GUI系统设计

一、GUI架构设计(基于App Designer) % 创建GUI组件 fig = uifigure(Name,图像融合拼接系统,Position,[100,100,800,600]);% 控件布局 btnLoad = uibutton(fig,Text,加载图像,Position,[20,500,100,30],...ButtonPushedFcn,@(btn,event) loadImageCallback());btnPreprocess =…...

Python使用多线程和异步调用

概述 在 Python 中,多线程和异步调用是处理并发任务的两种常用方式,适用于不同场景。 多线程(threading 模块) 多线程适合处理 I/O 密集型任务(如网络请求、文件读写),因为这类任务大部分时间在等待,线程可以在等待时切换到其他任务。 import threading import timedef…...

研究生学术英语读写教程(中国科学院大学出版) Unit10 TextA 原文以及翻译(仅供学习)

本文全程使用kimi助手识别原书文字并翻译,无人工校准,没有参考任何其他翻译文章,仅供学习使用,如有侵权请联系我,会及时删除。 The Doctors Dilemma: Is It Ever Good to Do Harm? 原文1 Medical knowledge changes swiftly, and technological changes make new and exp…...

基于Python+Vue开发的蛋糕商城管理系统源码+运行步骤

项目简介该项目是基于Python+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Python的蛋糕商城管理系统项目,大学生可以在实践中学习和…...

某运营商智慧协同平台——构建高效、敏捷的运营管理新模式

项目背景 在某运营商数字化运营战略的指引下,我司携手该运营商,共同打造智慧协同运营平台。该平台旨在实现省市协作,赋能一线,通过引入君南信息的技术和服务支持,提升业务支撑效率、加强系统安全防护、增强平台功能与服务,以满足全省21个地市独立配置、维护和管理数据展示…...

go使用反射获取http.Request参数到结构体 - 实践

go使用反射获取http.Request参数到结构体 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace …...

基于MATLAB/Simulink的TI2000系列DSP模型设计

一、开发环境配置工具安装安装MATLAB R2023a + Simulink 安装TI C2000 Support Package(通过Add-On Explorer) 安装Code Composer Studio (CCS) v7.5+硬件连接将TI2000系列DSP开发板(如C28069)通过USB连接至PC 在CCS中完成设备驱动配置二、模型设计流程 1. 创建Simulink模型…...

nginx 常用参数

...

Python常见函数和代码示例

内置函数 print() - 输出信息到控制台 name = "Alice" age = 30 print("姓名:", name, "年龄:", age) # 输出多个值 print(f"姓名: {name}, 年龄: {age}") # 使用f-string格式化输出 print("姓名: {}, 年龄: {}".format(na…...

69-SQLite应用 - 详解

69-SQLite应用 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14…...

mysql 源码下载,从获取到安装的完整指南

你是否曾想过亲手剖析MySQL这个影响了整个互联网时代的数据库?本文将带你一步步获取MySQL源码,让你不仅能安装使用,更能深入探索其内部机制。 MySQL作为最流行的开源关系型数据库之一,其发展历程堪称传奇。从最初的免费开源到被Oracle收购,MySQL始终保持着强大的生命力。它…...

docker中centos7配置

拉取centos7镜像: docker pull centos:7 启动容器: docker run -d -it --privileged --name=test centos:7 /usr/sbin/init 进入容器: docker exec -it test /bin/sh centos7安装: #设置时区 timedatectl set-timezone Asia/Shanghai #安装crontab服务 yum install -y rsy…...

centos7虚拟机下系统环境配置

​1. 网络配置 网卡: nmcli d 网络查看: ip addr 网络配置文件: /etc/sysconfig/network-scripts/ifcfg-enoXXX BOOTPROTO=static;IPADDR=;GATEWAY=;NETMASK=255.255.255.0;ONBOOT=yes 重启网络服务: systemctl restart network.service 或:service network restart 配置D…...

CefSharp高版本问题

​最近做一个PC端功能,打算用CefSharp+vue3来做,但在设置cookie时,出现了怎么也设置不上的问题。以前用CefSharp+vue2做过PC端,思路是差不多的。开始觉得是vue3哪里的设置问题,没找到,那就将cookie打印出来,打印出来是空的。那么问题就出在CefSharp上了,由于安装新的Ce…...

前缀和pre,如何求总和:pre(r) - pre(l)(1 = l = r = n),以及|pre(r) - pre(l)|

前缀和pre,如何求总和:pre(r) - pre(l)(1 <= l <= r <= n),以及|pre(r) - pre(l)|我们假设 pre[i]: 数组前i个数的之和,这就是前缀和 计算所有下标对 (1 <= l <= r <= n) pre[r] - pre[l] 之和 如果数据量是 n <= 1e5,直接两个for循环暴力求解的话,时…...

P11537 [NOISG 2023 Finals] Toxic Gene 题解

先考虑如果所有的 T 已被排除,剩下的位置怎么判断是 R 还是 S。 注意到每种细菌可以在样本中放入任意多个,容易想到经典的套路:将 \(8\) 个位置一起处理,第 \(i\) 个在样本中出现 \(2^{i-1}\) 次,再加入一个 T。若结果 \(\land 2^{i-1}=2^{i-1}\),则第 \(i\) 个对应的位置…...

keil5中stm32相关记录

在Keil 5中如何建立一个STM32项目_keil cmsis-CSDN博客 keil中怎么使用中文语言_keil怎么设置中文-CSDN博客 STM32入门开发-详解GPIO口的配置与控制方式(以LED灯为例) - 知乎...

centos7中mysql环境配置

​mysql源: rpm -ivh http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm yum install mysql-server mysql-client libmysqlclient-dev mysql-devel MySQL-python远程连接: GRANT ALL PRIVILEGES ON *.* TO root@% IDENTIFIED BY 123456 ; flush privileges; 记…...

centos7中php环境配置

​php7源: rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm yum -y install php72w php72w-cli php72w-fpm php72w-common php72w-devel php72w-embedded php72w-gd ph…...

Symfony学习笔记 - 利用Doctrine开发一个学生信息的增删查改

现在在学习Symfony,Doctrine作为官方重点推荐的数库库Bundle,必须要试试! 1、创建Symfony的Demo的Web应用 symfony new symfony_webapp --webapp 正确安装后,目录应该是这样的:如果你的目录仅仅只有config和vendor目录,那就表明你没有安装完整。原因是symfony时,需要从h…...

如何在Nginx服务器配置https以及强制跳转https

...

centos7中安装protobuf-c

​前言 设备服务与设备端通讯,设备服务使用Go构建,使用protobuf格式与设备端通讯,设备端采用stm32系列mcu,使用C语言开发,所以要生成protobuf C语言版协议库。步骤1.准备 yum -y install autoconf automake libtool yum -y install gcc gcc-c++2.安装protobuf protobuf版本…...

赞助NYU-Poly女性网络安全研讨会:推动行业多元发展

本文介绍Trail of Bits公司赞助纽约大学理工学院女性网络安全研讨会的举措,包括活动目标、技术工作坊内容、职业发展指导以及往期参与记录,旨在促进网络安全领域的性别多元化。我们正在赞助NYU-Poly女性网络安全研讨会 Dan Guido 2014年9月29日 会议, 教育, 赞助 网络安全是一…...

MyEMS:开源能源管理的探索与实践

在当今社会,能源的有效管理与优化利用已成为企业、公共机构乃至全社会关注的核心议题。随着物联网(IoT)和大数据技术的成熟,相应的软件工具应运而生,旨在为解决能源挑战提供技术方案。MyEMS便是这一领域中的一个代表性开源项目。 什么是MyEMS? MyEMS是一个专为能源管理设…...

实时内核中的调度程序节流

实时内核包含一个保护机制,它允许分配供实时任务使用的带宽。保护机制被称为实时调度程序节流。 实时节流机制的默认值定义实时任务可以使用 95% 的 CPU 时间。其余的 5% 将被视为非实时任务,例如在 SCHED_OTHER 和类似调度策略下运行的任务。务必要注意,如果单个实时任务占…...

配置Burp Suite与Proxifier抓取微信小程序流量

微信小程序抓包教程:Burp Suite + Proxifier 配置指南 .container { max-width: 800px; margin: 0 auto; padding: 24px 40px; background-color: rgba(255, 255, 255, 1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); border-radius: 8px } .chart-container { position: rel…...

我的ai 相关工具站

在AI技术席卷日常生活的今天,美容与时尚领域也迎来了革新。如果你正在犹豫是否换发型、尝试新发色,或想看看不同年龄或面部效果的自己,RightHair.ai就是你的理想选择。这款完全免费的在线AI工具不仅能让你上传照片试穿200+种发型和发色,还提供AI年龄滤镜、微笑滤镜、瘦脸滤…...

C#第十一章 023 024

类 是一种数据结构析构器的声明 和构造器类似 ~Student(){}这样静态构造器是给静态属性的在类里面的类可以说是成员类或者嵌套类...

MyEMS:赋能每一个组织,成为自己的能源管理专家

能源管理曾是一件“昂贵”的事情。它意味着动辄七位数的软件许可费、依赖外部专家的深度定制,以及被特定供应商“锁定”的长期合约。这无形中为众多企业,特别是中小型企业和机构,筑起了一道难以逾越的高墙。 然而,数字时代的真正精神是“赋能”与“ democratization”(民主…...

Vue开发微信公众号上传图片

​处理思路:从服务器获取微信配置参数,进行微信配置 选择本地图片,获取图片base64输出 将base64图片转化为文件上传 关键代码: 1.获取配置与选择本地图片输出import http from ./http import api from ./api import wx from "weixin-js-sdk"; export default {g…...

centos7中scrapy运行环境配置

最近根据需要,使用scrapy开发了一个爬虫应用,直接使用的python2,记录一下部署环境。 1.安装epel扩展源 yum -y install epel-release 2.安装pip yum -y install python-pip3.安装scrapy pip install scrapy 阿里云镜像:pip install scrapy -i http://mirrors.aliyun.com/py…...

flutter配置国内镜像

git clone -b master https://mirrors.tuna.tsinghua.edu.cn/git/flutter-sdk.git设定方式如下: export FLUTTER_STORAGE_BASE_URL="https://mirrors.tuna.tsinghua.edu.cn/flutter" export PUB_HOSTED_URL="https://mirrors.tuna.tsinghua.edu.cn/dart-pub&qu…...

微信小程序 live-player 无声音

由于微信公众号在播放直播视频,方案上视频存在严重的延时,而小程序有live-player,可以做为低延时解决方案,所以准备改用小程序重写原来功能。问题描述: 1.微信小程序使用live-player控件播放基于腾讯lvb平台直播服务直播,视频由本地客户端,拉取摄像头视频向直播平台推流…...

栈的妙用:如何优雅地处理括号匹配难题 (C语言版)

栈的妙用:如何优雅地处理括号匹配难题 (C语言版)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace…...

食品包装 AI 视觉检测技术:原理、优势与数据应用解析

一、食品行业包装质检的核心技术痛点 在食品行业现代化生产体系中,包装质检作为保障食品安全与品质的关键环节,面临多维度技术挑战,具体体现在以下方面: 1、检测效率与产线速度不匹配 现代化食品生产线(如饮料灌装线、零食包装线)已实现高速运转,部分产线每分钟可完成数…...

电流探头的常见应用场景

电流探头是一种用于测量电流的传感器,广泛应用于电子、电力、通信等多个领域,其常见测试场景主要包括以下几类: 一、电子设备研发与调试 在电子设备的设计、研发和故障排查阶段,电流探头是关键工具,主要用于: 电路工作电流监测:测量各类电子电路(如主板、模块、芯片)的…...

WebRTC编码过载检测与帧率适应机制分析报告

WebRTC编码过载检测与帧率适应机制分析报告 1. 概述 本报告基于WebRTC源码分析,详细阐述了编码过载检测机制及其触发的帧率降级算法。分析范围涵盖从编码时间测量到最终帧率调整的完整调用链。 2. 编码使用率计算机制 2.1 基本计算公式 位置: android/cmake/src/video/adaptat…...

PC桌面应用开发选择

要使用Web方式,基本有3种方案可供选择: cef electron nwjs 1.cef情况下,.NET可以很好的支持,是个不错的方案 2.electron、nwjs主要在nodejs环境下开发,也是个不错选择 最后采用cef做壳,浏览器方式,Vue做页面形式开发。写于 2020-08-12...

陈燕的项目启动笔记

现在已经把项目起来了。 启动过程如下:1. 拉代码这里的前端的代码是缺少的,需要跟人要一下 2. 后端的mysql创建CREATE DATABASE IF NOT EXISTS lth_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 3. sql也有一些问题,把错误的sql都删除 4. mysql -u root -p 1234…...

C++面试宝典八股文之什么是封装、继承、多态(附面试宝典八股文PDF)

一、C++面试宝典&八股文 PDF文档自取:https://pan.quark.cn/s/5d4c5050d512 二、什么是封装、继承、多态? 1.封装 概念:封装是将数据(属性)和操作数据的方法(行为)捆绑在一起,形成一个独立的单元(即类),并尽可能隐藏类的内部实现细节,只保留有限的接口与外部交…...

无需复杂正则:SLS 新脱敏函数让隐私保护更简单高效

AI 时代海量交互数据推动智能应用快速发展,但其中的个人隐私信息也带来严峻的安全挑战。数据脱敏已从可选项转变为企业合规经营的必需品。作者:孙玉梅 背景 AI 时代海量交互数据推动智能应用快速发展,但其中的个人隐私信息也带来严峻的安全挑战。数据脱敏已从可选项转变为企…...

DRAM、SRAM、NAND Flash、NOR Flash、EEPROM、MRAM存储器你分得清吗?

DRAM、SRAM、NAND Flash、NOR Flash、EEPROM、MRAM存储器,这些是计算机和电子设备中最核心的几种存储器技术。 首先,我们可以从两个最根本的特性来对它们进行初步区分:​​易失性 (Volatile)​​:断电后数据是否丢失。​​读写特性​​:是像内存一样可以​​按字节随机读写…...

【初赛】最短路 次短路 k短路 - Slayer

最短路、次短路、k短路算法总结与C++代码示例 一、最短路算法 1. Dijkstra算法(单源最短路,非负权图)适用场景:有向/无向图,边权非负,求单源最短路径 时间复杂度:O(m log n)( n 为顶点数,m 为边数,使用优先队列+邻接表)2. Bellman-Ford 算法(单源最短路,支持负权图…...

hyperv 管理的 ubuntu 虚拟机压缩磁盘

1. 删除所有检查点,必须全部删除2. 多次执行 fstrim 命令sudo fstrim -av /: 488 GiB (498240180224 bytes) trimmed on /dev/sda2sudo fstrim -av /: 122 MiB (126992384 bytes) trimmed on /dev/sda2sudo fstrim -av /: 0 B (0 bytes) trimmed on /dev/sda2直到出现 0 B (0 …...