微服务高级篇(二):分布式事务+Seata架构

文章目录

  • 一、分布式事务理论基础
    • 1.1 CAP定理
    • 1.2 BASE理论
  • 二、初始Seata
    • 2.1 Seata的架构
    • 2.2 部署TC【事务协调者】服务
    • 2.3 微服务集成Seata
  • 三、实践
    • 3.1 XA模式
      • 3.1.1 原理
      • 3.1.2 实现
    • 3.2 AT模式
      • 3.2.1 原理
      • 3.2.2 脏写问题以及解决方案【全局锁+超时处理】
      • 3.2.3 实现
    • 3.3 TCC模式
      • 3.3.1 原理
      • 3.3.2 实现
    • 3.4 SAGA模式
    • 3.5 四种模式的对比
  • 四、高可用
    • 4.1 高可用集群结构
    • 4.2 实现


一、分布式事务理论基础

在分布式系统下,一个业务跨越多个服务或数据源,每个服务都是一个分支事务,要保证所有分支事务最终状态一致,这样的事务就是分布式事务。

1.1 CAP定理

1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标:

  1. Consistency(一致性):用户访问分布式系统中的任意节点,得到的数据必须一致
  2. Availability(可用性):用户访问集群中的任意健康节点,必须能得到响应,而不是超时或拒绝
  3. Partition tolerance (分区容错性):(1)artition(分区):因为网络故障或其它原因导致分布式系统中的部分节点与其它节点失去连接,形成独立分区。(2)Tolerance(容错):在集群出现分区时,整个系统也要持续对外提供服务

Eric Brewer 说,分布式系统无法同时满足这三个指标。这个结论就叫做 CAP 定理。

  1. 简述CAP定理内容? 分布式系统节点通过网络连接,一定会出现分区问题(P) 当分区出现时,系统的一致性(C)和可用性(A)就无法同时满足
  2. 思考:elasticsearch集群是CP还是AP? ES集群出现分区时,故障节点会被剔除集群,数据分片会重新分配到其它节点,保证数据一致。因此是低可用性,高一致性,属于CP

1.2 BASE理论

BASE理论是对CAP的一种解决思路,包含三个思想:

  1. Basically Available (基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
  2. Soft State(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态。
  3. Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。

而分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴CAP定理和BASE理论:

  1. AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致
  2. CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。

解决分布式事务,各个子系统之间必须能感知到彼此的事务状态,才能保证状态一致,因此需要一个事务协调者来协调每一个事务的参与者(子系统事务)。
这里的子系统事务,称为分支事务;有关联的各个分支事务在一起称为全局事务

  1. 简述BASE理论三个思想:基本可用、软状态、最终一致
  2. 解决分布式事务的思想和模型: 全局事务:整个分布式事务 分支事务:分布式事务中包含的每个子系统的事务 最终一致思想:各分支事务分别执行并提交,如果有不一致的情况,再想办法恢复数据
    强一致思想:各分支事务执行完业务不要提交,等待彼此结果。而后统一提交或回滚

二、初始Seata

2.1 Seata的架构

Seata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。致力于提供高性能和简单易用的分布式事务服务,为用户打造一站式的分布式解决方案。
官网地址:http://seata.io/,其中的文档、播客中提供了大量的使用说明、源码分析。

在这里插入图片描述

Seata提供了四种不同的分布式事务解决方案:
XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
TCC模式:最终一致的分阶段事务模式,有业务侵入
AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
SAGA模式:长事务模式,有业务侵入

2.2 部署TC【事务协调者】服务

  1. 下载包,然后修改conf目录下的registry.conf文件,这里我们用的是nacos 注意:serverAddr = "127.0.0.1:8848"地址要是nacos的启动地址
    registry.conf
registry {# tc服务的注册中心类,这里选择nacos,也可以是eureka、zookeeper等type = "nacos"nacos {# seata tc 服务注册到 nacos的服务名称,可以自定义application = "seata-tc-server"serverAddr = "127.0.0.1:8848"group = "DEFAULT_GROUP"namespace = ""cluster = "SH"username = "nacos"password = "nacos"}
}config {# 读取tc服务端的配置文件的方式,这里是从nacos配置中心读取,这样如果tc是集群,可以共享配置type = "nacos"# 配置nacos地址等信息nacos {serverAddr = "127.0.0.1:8848"namespace = ""group = "SEATA_GROUP"username = "nacos"password = "nacos"dataId = "seataServer.properties"}
}
  1. 特别注意,为了让tc服务的集群可以共享配置,我们选择了nacos作为统一配置中心。因此服务端配置文件seataServer.properties文件需要在nacos中配好。
    在这里插入图片描述
    配置内容如下:
# 数据存储方式,db代表数据库
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
# 事务、日志等配置
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000# 客户端与服务端传输方式
transport.serialization=seata
transport.compressor=none
# 关闭metrics功能,提高性能
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

其中的数据库地址、用户名、密码都需要修改成你自己的数据库信息。

  1. 创建数据库表
    特别注意:tc服务在管理分布式事务时,需要记录事务相关数据到数据库中,你需要提前创建好这些表。
    新建一个名为seata的数据库,运行课前资料提供的sql文件:
    这些表主要记录全局事务、分支事务、全局锁信息:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- 分支事务表
-- ----------------------------
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table`  (`branch_id` bigint(20) NOT NULL,`xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`transaction_id` bigint(20) NULL DEFAULT NULL,`resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`status` tinyint(4) NULL DEFAULT NULL,`client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`gmt_create` datetime(6) NULL DEFAULT NULL,`gmt_modified` datetime(6) NULL DEFAULT NULL,PRIMARY KEY (`branch_id`) USING BTREE,INDEX `idx_xid`(`xid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;-- ----------------------------
-- 全局事务表
-- ----------------------------
DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table`  (`xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`transaction_id` bigint(20) NULL DEFAULT NULL,`status` tinyint(4) NOT NULL,`application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`timeout` int(11) NULL DEFAULT NULL,`begin_time` bigint(20) NULL DEFAULT NULL,`application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`gmt_create` datetime NULL DEFAULT NULL,`gmt_modified` datetime NULL DEFAULT NULL,PRIMARY KEY (`xid`) USING BTREE,INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,INDEX `idx_transaction_id`(`transaction_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;
  1. 启动TC服务

进入bin目录,运行其中的seata-server.bat即可:

启动成功后,seata-server应该已经注册到nacos注册中心了。

打开浏览器,访问nacos地址:http://localhost:8848,然后进入服务列表页面,可以看到seata-tc-server的信息:

在这里插入图片描述

2.3 微服务集成Seata

第一步:引入相关依赖

        <!--seata--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><!--版本较低,因此排除--><exclusion><artifactId>seata-spring-boot-starter</artifactId><groupId>io.seata</groupId></exclusion></exclusions></dependency><!--seata starter采用1.4.2版本--><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>${seata.version}</version></dependency>

第二步:配置yml文件,让微服务通过注册中心找到seate-tc-server
在这里插入图片描述

第三步:在seata-server.bat控制台看到注册成功
在这里插入图片描述

三、实践

3.1 XA模式

3.1.1 原理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.1.2 实现

在这里插入图片描述
测试服务,当订单数超过库存时,事务会进行回滚,如下所示:
在这里插入图片描述

3.2 AT模式

3.2.1 原理

在这里插入图片描述

简述AT模式与XA模式最大的区别是什么?
XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
XA模式强一致;AT模式最终一致

3.2.2 脏写问题以及解决方案【全局锁+超时处理】

  1. AT模式存在脏写问题:一个事务A修改完数据释放DB锁,事务B又获得DB锁修改数据后释放锁,此时A出错,获得DB锁根据快照恢复数据,会导致事务B对数据的修改丢失
    在这里插入图片描述

  2. 上述问题可以通过全局锁来解决:当事务2执行业务后想要获取全局锁,而事务1回滚也需要DB锁,这样会形成死锁问题;解决办法是事务2等待一段时间无法获取全局锁,就回滚并释放DB锁;这样就解决了脏写和死锁问题。
    在这里插入图片描述

  3. 但是全局锁是由seata管理的,而非seata管理的事务要和seata管理的事物修改一个数据时,就不需要使用全局锁,这样又会回到脏写问题。AT模式其实对这个问题也会处理,由于保存快照时会生成两个快照【修改前快照、修改后快照】,当事务1要回滚时比对修改后快照,发现数据被非seata管理的事物修改了,就给通知人工处理。

在这里插入图片描述

总结:AT模式虽然隔离性比较差,但是可以利用全局锁实现读写隔离
在这里插入图片描述

3.2.3 实现

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.3 TCC模式

3.3.1 原理

前两种模式都要加锁来保证隔离性,性能会变差;TCC模式通过人工编码大大提高了效率。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.3.2 实现

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第一步:创建冻结金额表【包括:冻结金额、事务状态等】

在这里插入图片描述

第二步:编写业务【try、confrim、cancel】逻辑,判断空回滚和业务悬挂

在这里插入图片描述

AccountTCCService.java

@LocalTCC
public interface AccountTCCService {@TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,@BusinessActionContextParameter(paramName = "money")int money);boolean confirm(BusinessActionContext ctx);boolean cancel(BusinessActionContext ctx);
}

AccountTCCServiceImpl.java

@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {@Autowiredprivate AccountMapper accountMapper;@Autowiredprivate AccountFreezeMapper freezeMapper;@Override@Transactionalpublic void deduct(String userId, int money) {// 0.获取事务id = RootContext.getXID();String xid = RootContext.getXID();/** 1. 避免业务悬挂:即在try之前,不能有cancel* 判断freeze中是否有记录,如果有,表示cancel执行过,* 不能执行业务try*/if(freezeMapper.selectById(xid) != null){// cancel执行过了,拒绝业务return;}// 2.扣减可用余额accountMapper.deduct(userId, money);// 3.记录冻结金额,事务状态AccountFreeze freeze = new AccountFreeze();freeze.setUserId(userId);freeze.setFreezeMoney(money);freeze.setState(AccountFreeze.State.TRY);freeze.setXid(xid);freezeMapper.insert(freeze);}@Overridepublic boolean confirm(BusinessActionContext ctx) {// 1.获取事务idString xid = ctx.getXid();// 2.根据id删除冻结记录int count = freezeMapper.deleteById(xid);return count == 1;}@Overridepublic boolean cancel(BusinessActionContext ctx) {// 0.查询冻结记录String xid = ctx.getXid();AccountFreeze freeze = freezeMapper.selectById(xid);/** 1.空回滚判断* 判断freeze若为null,证明try没执行,需要空回滚*/if (freeze == null) {// 从上下文获取useridString userId = ctx.getActionContext("userId").toString();// 插入一条空数据AccountFreeze freeze1 = new AccountFreeze();freeze1.setUserId(userId);freeze1.setFreezeMoney(0);freeze1.setState(AccountFreeze.State.CANCEL);freeze1.setXid(xid);freezeMapper.insert(freeze);return true;}/** 2. 判断幂等(cancel不能执行多次)* 看状态是否为cancel*/if (freeze.getState() == 3) {// 已经处理一次cancel,无需再次cancelreturn true;}// 3.恢复可用余额accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());// 4.将冻结金额清零,状态改为CANCELfreeze.setFreezeMoney(0);freeze.setState(AccountFreeze.State.CANCEL);int count = freezeMapper.updateById(freeze);return count == 1;}
}

第三步:测试
在这里插入图片描述

3.4 SAGA模式

在这里插入图片描述

3.5 四种模式的对比

在这里插入图片描述

四、高可用

4.1 高可用集群结构

服务找到集群?
方式一:通过代码中的配置文件,但是一旦集群变了就要修改代码不方便;
方式二:nacos的热更新,将配置文件放到nacos的配置中心,随时更新。
在这里插入图片描述

4.2 实现

  1. 模拟异地容灾的TC集群
    计划启动两台seata的tc服务节点:
节点名称ip地址端口号集群名称
seata127.0.0.18091SH
seata2127.0.0.18092HZ

之前我们已经启动了一台seata服务,端口是8091,集群名为SH。

现在,将seata目录复制一份,起名为seata2

修改seata2/conf/registry.conf内容如下:直接修改集群即可

registry {# tc服务的注册中心类,这里选择nacos,也可以是eureka、zookeeper等type = "nacos"nacos {# seata tc 服务注册到 nacos的服务名称,可以自定义application = "seata-tc-server"serverAddr = "127.0.0.1:8848"group = "DEFAULT_GROUP"namespace = ""cluster = "HZ"username = "nacos"password = "nacos"}
}config {# 读取tc服务端的配置文件的方式,这里是从nacos配置中心读取,这样如果tc是集群,可以共享配置type = "nacos"# 配置nacos地址等信息nacos {serverAddr = "127.0.0.1:8848"namespace = ""group = "SEATA_GROUP"username = "nacos"password = "nacos"dataId = "seataServer.properties"}
}

进入seata2/bin目录,然后运行命令:

seata-server.bat -p 8092

打开nacos控制台,查看服务列表:
在这里插入图片描述

点进详情查看:

在这里插入图片描述

  1. 将事务组映射配置到nacos

接下来,我们需要将tx-service-group与cluster的映射关系都配置到nacos配置中心。

新建一个配置:

配置的内容如下:

# 事务组映射关系
service.vgroupMapping.seata-demo=SHservice.enableDegrade=false
service.disableGlobalTransaction=false
# 与TC服务的通信配置
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableClientBatchSendRequest=false
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
# RM配置
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=false
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
# TM配置
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000# undo日志配置
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
client.log.exceptionRate=100
  1. 微服务读取nacos配置

接下来,需要修改每一个微服务的application.yml文件,让微服务读取nacos中的client.properties文件:

seata:config:type: nacosnacos:server-addr: 127.0.0.1:8848username: nacospassword: nacosgroup: SEATA_GROUPdata-id: client.properties
  1. 重启微服务,现在微服务到底是连接tc的SH集群,还是tc的HZ集群,都统一由nacos的client.properties来决定了。由于client.properties设置的集群是HZ,所以重启服务后,三个服务都到了HZ(端口号8091)中。
    在这里插入图片描述

  2. 现在修改client.properties设置的集群是SH,所以重启服务后,三个服务都到了SH(端口号8092)中。
    在这里插入图片描述

  3. 此时还可以看到orderApplication等从SH(8091端口)集群转到了HZ(8092端口)集群

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单记录一次帮维修手机经历(Vivo x9)

简介 手边有一台朋友亲戚之前坏掉的Vivo X9手机&#xff0c; 一直说要我帮忙修理一下&#xff0c; 我一直是拒绝的&#xff0c; 因为搞程序的不等于维修的&#xff08;会电脑不等于维修电器&#xff09;&#xff0c;不知道这种思路如何根深蒂固的&#xff0c;不过好吧&#xff…

选电气还是电子?哪个更有前途?

点击上方选择“置顶/星标公众号” 福利干货&#xff0c;第一时间送达 大家好&#xff0c;我是麦哥&#xff0c;最近有小伙伴在 星球 里提问; 提问内容 球友提问&#xff1a; 麦哥你好&#xff0c;我是电子电工专业的中职生一枚&#xff0c;今年参加职教高考能上个大专&#xff…

Axure案例分享—折叠面板(附下载地址)

今天和大家分享的Axure案例是折叠面板 折叠面板是移动端APP中常见的组件之一&#xff0c;有时候也称之为手风琴。咱们先看下Axure画出的折叠面板原型效果&#xff0c;然后再对该组件进行详细讲解。 一、功能介绍 折叠或展开多个面板内容&#xff0c;默认为展开一项内容&…

Spring Cloud Gateway教程

1 微服务网关概述 Spring Cloud Gateway是在 Spring 生态系统之上构建的API网关服务&#xff0c;旨在为微服务架构应用提供一种简单有效的统一的API路由管理方式。 Spring Cloud Gateway主要功能&#xff1a; 反向代理认证鉴权流量控制熔断日志监控 2 Spring Cloud Gateway三…

vue3与Electron构建跨平台应用(webpack)

一、创建vue3项目 vue create vue3_webpack_electron 二、安装Electron npm install --save-dev electron Electron 三、vue add electron-builder vue add electron-builder

Git和本地仓库托管到gitee

Git作用&#xff1a;记录代码内容&#xff0c;切换代码版本&#xff0c;实现多人开发 Git安装&#xff1a; 打开bash端 命令&#xff1a;git-v(查看版本&#xff09; 配置用户信息 git config --global user.name “用户名” git config --global user.email "邮箱名…

颠覆传统:Web3如何塑造未来的数字经济

引言 近年来&#xff0c;随着数字化时代的到来&#xff0c;互联网已经成为人们生活中不可或缺的一部分。然而&#xff0c;随着技术的不断发展和社会的不断变迁&#xff0c;传统的Web2模式逐渐显露出一些弊端&#xff0c;如数据垄断、隐私泄露等问题&#xff0c;这促使人们寻求…

【数据结构】——线性表(顺序表加链表),万字解读(加链表oj详解)

前言 由于之前存在过对两者的区别考虑&#xff0c;所以把他们放在一起来说&#xff0c;更加容易区别和理解 对于有关线性表的概念这里就不展示了&#xff0c;这里主要是介绍线性表里面的这两个结构的知识点 一.顺序表 1.顺序表介绍 顺序表的存储结构和逻辑结构都是相邻的&a…

阿里云轻量应用服务器和ECS服务器有啥区别?2024年整理对比表

阿里云服务器ECS和轻量应用服务器有什么区别&#xff1f;轻量和ECS优缺点对比&#xff0c;云服务器ECS是明星级云产品&#xff0c;适合企业专业级的使用场景&#xff0c;轻量应用服务器是在ECS的基础上推出的轻量级云服务器&#xff0c;适合个人开发者单机应用访问量不高的网站…

02分布式搜索引擎ES

elasticsearch查询 1.DSL查询文档1.1.DSL查询分类1.2.全文检索查询1.3.精准查询1.4.地理坐标查询1.5.复合查询 2.搜索结果处理2.1.排序2.2.分页2.3.高亮2.4.总结 3.RestClient查询文档3.1.快速入门3.2.match查询3.3.精确查询3.4.布尔查询3.5.排序、分页3.6.高亮 1.DSL查询文档 …

JetPack之LiveData

目录 一、LiveData简介1.1 LiveData是什么&#xff1f; 二、LiveData使用2.1 LiveData基础使用2.2 LiveData搭配Service模拟后台消息2.3 LiveData在组件中的数据传递 三、LiveData应用场景 一、LiveData简介 1.1 LiveData是什么&#xff1f; LiveData是一种可观察的数据存储器…

Golang 异步(bsd/linux)io

Golang 异步(bsd/linux)io 在日常开发中&#xff0c;读写文件的底层调用函数是syscall.Read/Write。一切都是围绕这两个函数展开的&#xff0c;不过有时候需要或者就是单纯想异步执行。liburing是linux上一个很好的原生异步io库&#xff0c;这里需要适配bsd派系的系统&#xf…

iostream、fstream、sstream、string、vector、unordered_map、stack

iostream 用于输入输出操作&#xff0c;包含了处理标准输入输出流的功能&#xff08;例如&#xff0c;cin, cout, cerr等&#xff09;。 #include <iostream>int main() {int number;std::cout << "Enter a number: ";std::cin >> number;std::…

像uniapp image标签一样对图片进行缩放和裁剪

像uniapp image标签一样对图片进行缩放和裁剪 0 前言提示1 实现1.1 不保持纵横比缩放图片&#xff0c;使图片的宽高完全拉伸至填满 image 元素1.2 保持纵横比缩放图片&#xff0c;使图片的长边能完全显示出来。也就是说&#xff0c;可以完整地将图片显示出来。1.3 保持纵横比缩…

Amuse .NET application for stable diffusion

Amuse github地址&#xff1a;https://github.com/tianleiwu/Amuse .NET application for stable diffusion, Leveraging OnnxStack, Amuse seamlessly integrates many StableDiffusion capabilities all within the .NET eco-system Welcome to Amuse! Amuse is a profes…

uni-app 中两个系统各自显示不同的tabBar

最近在一个uni-app项目中遇到一个需求,在登录页面成功登录以后需要判断身份,不同的身份的进入不同的tabBar页面,但是在uni-app项目中pages.json中的tabBar的list数组只有一个&#xff0c;且不能写成动态的,那如何实现这个需求呢?答案是需要我们自定义tabBar。 目录 1、我们确…

vue+elementUI实现树形穿梭框

1.实现效果 2.整体思路 将左侧选中的节点移动到右侧&#xff0c;还要保持树结构&#xff0c;意味着移动子节点&#xff0c;需要把该子节点对应的父节点甚至父节点的父节点一并移到右侧形成一个新的树结构&#xff0c;树结构的层级和原来的树保持一致&#xff0c;只是右侧展示…

QML 绘制PieSeries(饼状图)

一.PieSeries(饼状图)介绍 在QML中绘制饼状图主要依赖于Qt提供的QtCharts模块。该模块包含了一系列用于绘制图表的类&#xff0c;其中PieSeries类专门用于创建饼状图。 以下是一些关于使用QtCharts在QML中绘制饼状图的介绍&#xff1a; PieSeries属性&#xff1a;PieSeries是绘…

Sora后时代文生视频的探索

一、写在前面 按常理&#xff0c;这里应该长篇大论地介绍一下Sora发布对各行业各方面产生的影响。不过&#xff0c;这类文章已经很多了&#xff0c;我们今天主要聊聊那些已经成熟的解决方案、那些已经可以“信手拈来”的成果&#xff0c;并以此为基础&#xff0c;看看Sora发布…

练习实践-TLS协议01-Wireshark对https数据的解密

参考来源&#xff1a; https://zhuanlan.zhihu.com/p/36669377 https://blog.csdn.net/u010726042/article/details/53408077 思路&#xff1a; wireshark抓到的https流量包经过了ssl加密&#xff0c;那么我们如何才能查看解密的数据呢&#xff1f;Firefox和Chrome浏览器都支…