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

[000-01-008].Seata案例应用

  • 业务说明:这里我们创建三个服务,一个订单服务,一个库存服务,一个账户服务
  • 当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品的库存;再通过远程调用账户服务来扣减用户账户里面的余额;最后在订单服务中修改订单状态为已完成。该操作跨越三个数据库,有两次远程调用,很明显会有分布式事务问题

在这里插入图片描述

6.1.数据库表准备

a.建三个数据库

CREATE DATABASE seata_order;
CREATE DATABASE seata_storage;
CREATE DATABASE seata_account;

在这里插入图片描述

b.undo_log回滚日志表

  • 1.按照上述的3个数据库分别对应的undo_log回滚日志表
  • 2.seata官网
  • 3.undo_log建表SQL如下:AT模式专用的,其他模式都不需要
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(`branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',`xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',`context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',`log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',`log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',`log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);

在这里插入图片描述

c.按照3个库分别对应业务表:

CREATE TABLE t_order(
`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
`product_id` BIGINT(11)DEFAULT NULL COMMENT '产品id',
`count` INT(11) DEFAULT NULL COMMENT '数量',
`money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额',
`status` INT(1) DEFAULT NULL COMMENT '订单状态: 0:创建中; 1:已完结'
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
SELECT * FROM t_order;
CREATE TABLE t_account(
`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
`user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
`total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',
`used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用账户余额',
`residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度'
)ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO t_account(`id`,`user_id`,`total`,`used`,`residue`)VALUES('1','1','1000','0','1000');
SELECT * FROM t_account;
CREATE TABLE t_storage(
`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
`total` INT(11) DEFAULT NULL COMMENT '总库存',
`used` INT(11) DEFAULT NULL COMMENT '已用库存',
`residue` INT(11) DEFAULT NULL COMMENT '剩余库存'
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO t_storage(`id`,`product_id`,`total`,`used`,`residue`)VALUES('1','1','100','0','100');SELECT * FROM t_storage;

d.最终的效果:

库表图:

在这里插入图片描述

所有的SQL:

  • 1.建seata_order库 + 建t_order表 + undo_log表:
#orderCREATE DATABASE seata_order;USE seata_order;CREATE TABLE t_order(`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,`user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',`product_id` BIGINT(11)DEFAULT NULL COMMENT '产品id',`count` INT(11) DEFAULT NULL COMMENT '数量',`money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额',`status` INT(1) DEFAULT NULL COMMENT '订单状态: 0:创建中; 1:已完结')ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;SELECT * FROM t_order;-- for AT mode you must to init this sql for you business database. the seata server not need it.CREATE TABLE IF NOT EXISTS `undo_log`(`branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',`xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',`context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',`log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',`log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',`log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);
  • 2.建seata_storage库 + 建t_storage表 + undo_log表:
#storageCREATE DATABASE seata_storage;USE seata_storage;CREATE TABLE t_storage(`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,`product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',`total` INT(11) DEFAULT NULL COMMENT '总库存',`used` INT(11) DEFAULT NULL COMMENT '已用库存',`residue` INT(11) DEFAULT NULL COMMENT '剩余库存')ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO t_storage(`id`,`product_id`,`total`,`used`,`residue`)VALUES('1','1','100','0','100');SELECT * FROM t_storage;-- for AT mode you must to init this sql for you business database. the seata server not need it.CREATE TABLE IF NOT EXISTS `undo_log`(`branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',`xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',`context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',`log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',`log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',`log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);
  • 3.建seata_account库 + 建t_account表 + undo_log表:
#accountcreate database seata_account;use seata_account;CREATE TABLE t_account(`id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',`user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',`total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',`used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余额',`residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度')ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;INSERT INTO t_account(`id`,`user_id`,`total`,`used`,`residue`)VALUES('1','1','1000','0','1000');SELECT * FROM t_account;-- for AT mode you must to init this sql for you business database. the seata server not need it.CREATE TABLE IF NOT EXISTS `undo_log`(`branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',`xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',`context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',`rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',`log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',`log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',`log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);

6.2.微服务编码和落地实现:

整个业务流程:下订单 -> 减库存 ->扣余额 -> 改订单状态

a.MyBatis一键生成:

config.properties

#t_pay表包名
package.name=com.atguigu.cloud# mysql8.0
jdbc.driverClass = com.mysql.cj.jdbc.Driver
jdbc.url= jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
jdbc.user = root
jdbc.password =123456# seata_order
#jdbc.driverClass = com.mysql.cj.jdbc.Driver
#jdbc.url = jdbc:mysql://localhost:3306/seata_order?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
#jdbc.user = root
#jdbc.password =123456# seata_storage
#jdbc.driverClass = com.mysql.cj.jdbc.Driver
#jdbc.url = jdbc:mysql://localhost:3306/seata_storage?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
#jdbc.user = root
#jdbc.password =123456# seata_account
#jdbc.driverClass = com.mysql.cj.jdbc.Driver
#jdbc.url = jdbc:mysql://localhost:3306/seata_account?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
#jdbc.user = root
#jdbc.password =123456

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><properties resource="config.properties"/><context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"><property name="beginningDelimiter" value="`"/><property name="endingDelimiter" value="`"/><plugin type="tk.mybatis.mapper.generator.MapperPlugin"><property name="mappers" value="tk.mybatis.mapper.common.Mapper"/><property name="caseSensitive" value="true"/></plugin><jdbcConnection driverClass="${jdbc.driverClass}"connectionURL="${jdbc.url}"userId="${jdbc.user}"password="${jdbc.password}"></jdbcConnection><javaModelGenerator targetPackage="${package.name}.entities" targetProject="src/main/java"/><sqlMapGenerator targetPackage="${package.name}.mapper" targetProject="src/main/java"/><javaClientGenerator targetPackage="${package.name}.mapper" targetProject="src/main/java" type="XMLMAPPER"/><table tableName="t_pay" domainObjectName="Pay"><generatedKey column="id" sqlStatement="JDBC"/></table><!--  seata_order --><!--<table tableName="t_order" domainObjectName="Order"><generatedKey column="id" sqlStatement="JDBC"/></table>--><!--seata_storage--><!--<table tableName="t_storage" domainObjectName="Storage"><generatedKey column="id" sqlStatement="JDBC"/></table>--><!--seata_account--><!--<table tableName="t_account" domainObjectName="Account"><generatedKey column="id" sqlStatement="JDBC"/></table>--></context>
</generatorConfiguration>

b.修改公共cloud-api-commons模块:

新增库存和账户两个Feign服务接口

  • 1.StorageFeignApi.java
package com.atguigu.cloud.apis;
import com.atguigu.cloud.resp.ResultData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** @auther zzyy* @create 2023-12-01 17:41*/
@FeignClient(value = "seata-storage-service")
public interface StorageFeignApi
{/*** 扣减库存*/@PostMapping(value = "/storage/decrease")ResultData decrease(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}
  • 2.AccountFeignApi.java
package com.atguigu.cloud.apis;import com.atguigu.cloud.resp.ResultData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** @auther zzyy* @create 2023-12-01 17:42*/
@FeignClient(value = "seata-account-service")
public interface AccountFeignApi
{//扣减账户余额@PostMapping("/account/decrease")ResultData decrease(@RequestParam("userId") Long userId, @RequestParam("money") Long money);
}

d.新建订单Order微服务

e.新建库存Storag微服务

c.新建账户Account微服务

6.3.测试

b.


相关文章:

[000-01-008].Seata案例应用

业务说明&#xff1a;这里我们创建三个服务&#xff0c;一个订单服务&#xff0c;一个库存服务&#xff0c;一个账户服务。当用户下单时&#xff0c;会在订单服务中创建一个订单&#xff0c;然后通过远程调用库存服务来扣减下单商品的库存&#xff1b;再通过远程调用账户服务来…...

超详细!!!electron-vite-vue开发桌面应用之创建新窗口以及主进程和子进程的通信监听(十二)

云风网 云风笔记 云风知识库 一、新建打开窗口 1、在electron/main.ts中加入主进程打开窗口逻辑代码 import { ipcMain } from "electron"; ipcMain.handle("open-win", (_, arg) > {const childWindow new BrowserWindow({webPreferences: {preloa…...

java编辑器——IntelliJ IDEA

java编辑器有两种选择——IntelliJ IDEA和VsCode。其中IntelliJ IDEA现在是企业用的比较多的&#xff0c;是专门为java设计的&#xff0c;而VsCode则是通过插件来实现Java编辑的。 1.IntelliJ IDEA 官网下载链接&#xff1a;https://www.jetbrains.com/idea/ 注意选择社区版…...

经验笔记:SSL证书

SSL证书经验笔记 1. 什么是SSL证书&#xff1f; SSL&#xff08;Secure Sockets Layer&#xff09;证书是一种数字证书&#xff0c;用于在客户端&#xff08;如浏览器&#xff09;和服务器之间建立加密连接&#xff0c;以确保数据传输的安全性。随着互联网的发展&#xff0c;…...

设计模式之装饰器模式:让对象功能扩展更优雅的艺术

一、什么是装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff08;Structural Pattern&#xff09;&#xff0c;它允许用户通过一种灵活的方式来动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;装饰器模式相比使用…...

Anchor Alignment Metric来优化目标检测的标签分配和损失函数。

文章目录 背景假设情况任务和目标TaskAligned方法的应用1. **计算Anchor Alignment Metric**2. **动态样本分配**3. **调整损失函数** 示例总结 背景 假设我们在进行目标检测任务&#xff0c;并且使用了YOLOv8模型。我们希望通过TaskAligned方法来优化Anchor与目标的匹配程度&…...

C++---由优先级队列认识仿函数

文章目录 一、优先级队列是什么&#xff1f; 二、如何使用优先级队列 1、优先级队列容器用法 2、为什么容器本身无序&#xff1f; 三、什么是仿函数&#xff1f; 1. 什么是仿函数&#xff1f; 2. 仿函数的优势 四、仿函数如何使用&#xff1f; 1、重载operator()函数 2、运用第…...

Client访问Server访问慢的原因

1. 网络层面的问题 网络延迟&#xff1a;客户端与服务器之间的地理距离较远(跨ISP、路径次优&#xff09;&#xff0c;导致高网络延迟&#xff08;如高 RTT 值&#xff09;。使用 ping 或 traceroute 工具可以帮助定位网络延迟的来源 - mtr: 结合了ping和traceroute功能&#…...

用RPC Performance Inspector 优化你的区块链

目录 什么是RPC&#xff1f; RPC Performance Inspector 是做什么的&#xff1f; 为什么需要这个工具&#xff1f; 如何使用它&#xff1f; 适合谁用&#xff1f; 如何使用&#xff1f; 什么是RPC&#xff1f; RPC Performance Inspector 是一个专门用于测试和分析RPC性能…...

linux如何查看内存条是ddr几代

在 Linux 系统中&#xff0c;可以通过以下几种方法查看内存条的类型和代数&#xff08;如 DDR3、DDR4 等&#xff09;&#xff1a; 1. 使用 dmidecode 命令 dmidecode 是一个工具&#xff0c;它可以从系统的 DMI 表&#xff08;也称为 SMBIOS 表&#xff09;中提取硬件信息&a…...

LeetCode 3153.所有数对中数位差之和:计数

【LetMeFly】3153.所有数对中数位差之和&#xff1a;计数 力扣题目链接&#xff1a;https://leetcode.cn/problems/sum-of-digit-differences-of-all-pairs/ 车尔尼有一个数组 nums &#xff0c;它只包含 正 整数&#xff0c;所有正整数的数位长度都 相同 。 两个整数的 数位…...

Spring Boot 整合 Sentinel 实现流量控制

在微服务架构中&#xff0c;流量控制是保障系统稳定性和高可用性的关键技术之一。阿里巴巴开源的 Sentinel 是一款面向分布式系统的流量防护组件&#xff0c;旨在从流量控制、熔断降级、系统负载保护等多个维度保障服务的稳定性。本文将详细介绍如何在 Spring Boot 项目中整合 …...

Elasticsearch倒排索引

什么是倒排索引 倒排索引&#xff08;Inverted Index&#xff09;是一种将文档中的每个单词映射到包含该单词的文档列表上的数据结构 倒排索引的构建过程 文档1: “我爱吃苹果” 文档2: “我爱吃香蕉” 文档3: “我喜欢苹果和香蕉” 文档分词&#xff1a;将文档中的文本内容…...

速盾:ddos常用防御方法是什么?

DDoS攻击是一种通过向网络资源发送大量请求或大流量数据来使其过载的攻击手段。为了应对这种攻击&#xff0c;常用的防御方法可以分为三个层次&#xff1a;流量清洗、服务器升级和高防CDN。 流量清洗是一种基础的防御手段&#xff0c;它通过过滤和识别恶意流量来阻止DDoS攻击。…...

二分算法入门(简单题)

习题1 704. 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], targ…...

在使用React Hooks中,如何避免状态更新时的性能问题?

在React Hooks中避免状态更新时的性能问题&#xff0c;可以采取以下一些最佳实践&#xff1a; 避免不必要的状态更新&#xff1a; 使用React.memo、useMemo、和useCallback来避免组件或其子组件进行不必要的渲染。 使用useMemo&#xff1a; 对于基于状态或props的复杂计算&…...

Pytest插件pytest-selenium-让自动化测试更简洁

在现代Web应用的开发中&#xff0c;自动化测试成为确保网站质量的重要手段之一。而Pytest插件 pytest-selenium 则为开发者提供了简单而强大的工具&#xff0c;以便于使用Python进行Web应用的自动化测试。本文将深入介绍 pytest-selenium 插件的基本用法和实际案例&#xff0c;…...

视觉语言模型(VLMs)知多少?

最近这几年&#xff0c;自然语言处理和计算机视觉这两大领域真是突飞猛进&#xff0c;让机器不仅能看懂文字&#xff0c;还能理解图片。这两个领域的结合&#xff0c;催生了视觉语言模型&#xff0c;也就是Vision language models (VLMs) &#xff0c;它们能同时处理视觉信息和…...

重新修改 Qt 项目的 Kit 配置

要重新修改 Qt 项目的 Kit 配置&#xff0c;你可以按照以下步骤进行操作&#xff1a; 1. 打开 Qt Creator 首先&#xff0c;启动 Qt Creator&#xff0c;确保你的项目已经打开。 2. 进入项目设置 在 Qt Creator 中&#xff0c;点击菜单栏的 “Projects” 标签&#xff08;通…...

【Spring Boot 3】【Web】自定义响应状态码

【Spring Boot 3】【Web】自定义响应状态码 背景介绍开发环境开发步骤及源码工程目录结构背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...