【分布式技术专题】「架构实践于案例分析」总结和盘点目前常用分布式事务特别及问题分析(Seata-终)

news2024/10/7 14:21:59

分布式事务中间件对⽐与选择

  • tx-lcn
  • EasyTransaction
  • ByteTCC
  • Seata

Seata实现分布式事务

我们主要以Seata的分布式事务框架进行介绍分析,相关的并且针对于其三种模式进行分别说明介绍。

搭建Seata Server

前往https://github.com/seata/seata/releases 下载Seata安装包,本书使⽤Seata 1.0.0。将⽬录切换⾄Seata根⽬录,根据操作系统,执⾏对应命令,即可启动Seata Server。

Linux/Unix/Mac

sh ./bin/seata-server.sh

Windows

bin\seata-server.bat

启动时,也可指定参数

$ sh ./bin/seata-server.sh -p 8091 -h 127.0.0.1 -m file
⽀持的参数如下表所示

Seata AT模式

  • ⼀阶段业务数据和回滚⽇志记录在同⼀个本地事务中提交,释放本地锁和连接资源。
  • ⼆阶段提交异步化,⾮常快速地完成。回滚通过⼀阶段的回滚⽇志进⾏反向补偿。
官⽅⽂档

http://seata.io/zh-cn/docs/dev/mode/at-mode.html

代码演示
Maven依赖
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
配置
seata:
   tx-service-group: content-center-seata-service-group
   service:
    vgroup-mapping:
        content-center-seata-service-group: seata-cluster
        grouplist:
           seata-cluster: 127.0.0.1:8091
           disable-global-transaction: false
配置说明
  • tx-service-group:事务分组,默认是 ${spring.application.name}-seata-service-group ,唯⼀即可。
  • vgroup-mapping:事务分组映射,表示 tx-service-group 对应到哪个Seata Server集群。
  • key是tx-service-group的值,value是集群名称,唯⼀即可
  • grouplist:集群中所包含的Seata Server的地址列表,key是vgroup-mapping中value的值,
  • value是Seata Server的地址列表
  • disable-global-transaction:是否开启全局事务开关,默认false。

在Seata1.0.0中,该配置⽆法正常读取,这是⼀个Bug,详⻅ https://github.com/seata/seata/issues/2114 ,好在,该配置的默认值就是false,所以不影响使⽤。

创建Seata事务记录表
-- auto-generated definition
create table undo_log (
id bigint auto_increment comment 'increment id' primary key,
branch_id bigint not null comment 'branch transaction id',
xid varchar(100) 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 not null comment '0:normal status,1:defense status',
log_created datetime not null comment 'create datetime',
log_modified datetime not null comment 'modify datetime',
constraint ux_undo_log
unique (xid, branch_id)
) comment 'AT transaction mode undo table' charset = utf8;
Controller代码:
private final ShareSeataService shareSeataService;
@PutMapping("/audit/seata1/{id}")
public Share auditByIdSeata1(@PathVariable Integer id, @RequestBody ShareAuditDTO auditDTO) {
     return this.shareSeataService.auditById(id, auditDTO);
}
Service代码:
  • 审核中心服务代码(含调用用户中心代码接口)
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ShareSeataService {
    private final ShareMapper shareMapper;
    private final UserCenterFeignClient userCenterFeignClient;

   @GlobalTransactional(rollbackFor = Exception.class)
    public Share auditById(Integer id, ShareAuditDTO auditDTO) {
        if (AuditStatusEnum.PASS.equals(auditDTO.getAuditStatusEnum())) { 
            userCenterFeignClient.addBonus(id, 50);
           // 故意抛异常,如果⽤户中⼼侧也能回滚,说明实现了分布式事务
          // throw new IllegalArgumentException("发⽣异常...");
        }
        this.auditByIdInDB(id, auditDTO);
        return this.shareMapper.selectByPrimaryKey(id);
   }
  • 审核中心服务代码(执行操作更新数据库机制)
    public void auditByIdInDB(Integer id, ShareAuditDTO auditDTO) {
        Share share = Share.builder().id(id).auditStatus(auditDTO.getAuditStatusEnum().toString()).reason(auditDTO.getReason())
       .build();
        this.shareMapper.updateByPrimaryKeySelective(share);
    }

@GlobalTransactional 注解⽤来创建分布式事务。

被调⽤⽅代码
Maven依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
配置
seata:
    tx-service-group: user-center-seata-service-group
      service:
      vgroup-mapping:
         user-center-seata-service-group: seata-cluster
         grouplist:
            seata-cluster: 127.0.0.1:8091
            disable-global-transaction: false

可以看出来,差距主要体现在tx-service-group的值。

Controller代码:
@GetMapping("/add-bonus/{id}/{bonus}")
public User addBonus(@PathVariable Integer id, @PathVariable Integer bonus) {
    this.userService.addBonus(id, bonus);
    return this.userService.findById(id);
}
Service代码:
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserService {
    private final UserMapper userMapper;
    private final BonusEventLogMapper bonusEventLogMapper;
    public User findById(Integer id) {
    // select * from user where id = #{id}
        return this.userMapper.selectByPrimaryKey(id);
    }

public void addBonus(Integer userId, Integer bonus) {
    // 1. 为⽤户加积分
    User user = this.userMapper.selectByPrimaryKey(userId);
    user.setBonus(user.getBonus() + bonus);
    this.userMapper.updateByPrimaryKeySelective(user);
    // 2. 记录⽇志到bonus_event_log表⾥⾯
    this.bonusEventLogMapper.insert(BonusEventLog.builder().userId(userId).value(bonus).event("CONTRIBUTE").createTime(new Date()).description("投稿加积分..").build());
    log.info("积分添加完毕...");
 }
}

Seata TCC模式

  • ⼀阶段 prepare ⾏为
  • ⼆阶段 commit 或 rollback ⾏为
需要实现的3个⽅法:
  • ⼀阶段:
    • ⽤于业务预处理的⽅法,即 Try 阶段、的⽅法,⽐如冻结⽤户的部分余额等等;
  • ⼆阶段:
    • ⽤于提交业务的⽅法,即 Commit ⽅法,⽐如扣除⽤户之前冻结的部分余额;
    • ⽤于回滚业务的⽅法,即 Rollback ⽅法,⽐如返还之前冻结的⽤户余额;
官⽅⽂档

http://seata.io/zh-cn/docs/dev/mode/tcc-mode.html

代码演示
行为操作接口
@LocalTCC
public interface TccActionOne {
   @TwoPhaseBusinessAction(name = "TccActionOne", commitMethod = "commit", rollbackMethod = "rollback")
    boolean prepare(BusinessActionContext actionContext, int a);
    boolean commit(BusinessActionContext actionContext);
    boolean rollback(BusinessActionContext actionContext);
}
接口实现类
  • 实现类1
@Component
public class TccActionOneImpl implements TccActionOne {
    @Override
    public boolean prepare(BusinessActionContext actionContext, int a) {
        // 这⾥是本地玩的,也可以调⽤其他微服务的接⼝
        String xid = actionContext.getXid();
        System.out.println("TccActionOne prepare, xid:" + xid);
        return true;
    }
    @Override
    public boolean commit(BusinessActionContext actionContext) {
        // 这⾥是本地玩的,也可以调⽤其他微服务的接⼝
        String xid = actionContext.getXid();
        System.out.println("TccActionOne commit, xid:" + xid);
        ResultHolder.setActionOneResult(xid, "T");
        return true;
    }
    @Override
    public boolean rollback(BusinessActionContext actionContext) {
        // 这⾥是本地玩的,也可以调⽤其他微服务的接⼝
        String xid = actionContext.getXid();
        System.out.println("TccActionOne rollback, xid:" + xid);
        ResultHolder.setActionOneResult(xid, "R");
        return true;
    }
}
@LocalTCC
public interface TccActionTwo {
    @TwoPhaseBusinessAction(name = "TccActionTwo", commitMethod = "commit", rollbackMethod = "rollback")
    boolean prepare(BusinessActionContext actionContext, int a);
    boolean commit(BusinessActionContext actionContext);
    boolean rollback(BusinessActionContext actionContext);
}
  • 实现类2
@Component
public class TccActionTwoImpl implements TccActionTwo {
       @Override
       public boolean prepare(BusinessActionContext actionContext, String b) {
              // 这⾥是本地玩的,也可以调⽤其他微服务的接⼝
              String xid = actionContext.getXid();
              System.out.println("TccActionTwo prepare, xid:" + xid);
              return true;
       }
       @Override
       public boolean commit(BusinessActionContext actionContext) {
              // 这⾥是本地玩的,也可以调⽤其他微服务的接⼝
              String xid = actionContext.getXid();
              System.out.println("TccActionTwo commit, xid:" + xid);
              ResultHolder.setActionTwoResult(xid, "T");
              return true;
       }
       @Override
       public boolean rollback(BusinessActionContext actionContext) {
              // 这⾥是本地玩的,也可以调⽤其他微服务的接⼝
              String xid = actionContext.getXid();
              System.out.println("TccActionTwo rollback, xid:" + xid);
              ResultHolder.setActionTwoResult(xid, "R");
              return true;
       }
}
  • 聚合实现服务业务实现类执行

@Service
public class ShareSeataService{

    @Autowired
    TccActionOne tccActionOne;

    @Autowired
    TccActionTwo tccActionTwo;

    @GlobalTransactional
    public void tccTransactionCommit(Map<String, String> paramMap) {
        //第一个TCC 事务参与者
        boolean result = tccActionOne.prepare(null, "one");
        if (!result) {
			paramMap.put("xid",RootContext.getXID());
            throw new RuntimeException("TccActionOne failed.");
        }
        List list = new ArrayList();
        list.add("c1");
        list.add("c2");
        result = tccActionTwo.prepare(null, "two");
        if (!result) {
            paramMap.put("xid",RootContext.getXID());
            throw new RuntimeException("TccActionTwo failed.");
        }
       paramMap.put("xid",RootContext.getXID());
        return ;
    }
}

// 回滚的代码相似,就不写了
  • 执行调用点
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ShareAdminController {
    private final ShareSeataService shareSeataService;
    @GetMapping("tcc-commit")
    public String tccTransactionCommit() {
        Map<String, String> map = new HashMap<>();
        this.shareSeataService.tccTransactionCommit(map);
        String xid = map.get("xid");
        // 结果T
        return ResultHolder.getActionOneResult(xid);
    }
    @GetMapping("/tcc-rollback")
    public String tccTransactionRollback() {
       Map<String, String> map = new HashMap<>();
       try {
          this.shareSeataService.tccTransactionRollback(map);
       } catch (Throwable t) {
          log.warn("事务回滚..", t);
       }
       String xid = map.get("xid");
       // 结果R
       return ResultHolder.getActionOneResult(xid);
   }
}
定义状态机⽂件:
{
    "Name": "reduceInventoryAndBalance",
    "Comment": "reduce inventory then reduce balance in a transaction",
    "StartState": "ReduceInventory",
    "Version": "0.0.1",
    "States": {
        "ReduceInventory": {
            "Type": "ServiceTask",
            "ServiceName": "inventoryAction",
            "ServiceMethod": "reduce",
            "CompensateState": "CompensateReduceInventory",
            "Next": "ChoiceState",
            "Input": [
                "$.[businessKey]",
                "$.[count]"
            ],
            "Output": {
                "reduceInventoryResult": "$.#root"
            },
            "Status": {
                "#root == true": "SU",
                "#root == false": "FA",
                "$Exception{java.lang.Throwable}": "UN"
            }
        },
        "ChoiceState": {
            "Type": "Choice",
            "Choices": [
                {
                    "Expression": "[reduceInventoryResult] == true",
                    "Next": "ReduceBalance"
                }
            ],
            "Default": "Fail"
        },
        "ReduceBalance": {
            "Type": "ServiceTask",
            "ServiceName": "balanceAction",
            "ServiceMethod": "reduce",
            "CompensateState": "CompensateReduceBalance",
            "Input": [
                "$.[businessKey]",
                "$.[amount]",
                {
                    "throwException": "$.[mockReduceBalanceFail]"分布式事务27
                }
            ],
            "Output": {
                "compensateReduceBalanceResult": "$.#root"
            },
            "Status": {
                "#root == true": "SU",
                "#root == false": "FA",
                "$Exception{java.lang.Throwable}": "UN"
            },
            "Catch": [
                {
                    "Exceptions": [
                        "java.lang.Throwable"
                    ],
                    "Next": "CompensationTrigger"
                }
            ],
            "Next": "Succeed"
        },
        "CompensateReduceInventory": {
            "Type": "ServiceTask",
            "ServiceName": "inventoryAction",
            "ServiceMethod": "compensateReduce",
            "Input": [
                "$.[businessKey]"
            ]
        },
        "CompensateReduceBalance": {
            "Type": "ServiceTask",
            "ServiceName": "balanceAction",
            "ServiceMethod": "compensateReduce",
            "Input": [
                "$.[businessKey]"
            ]
        },
        "CompensationTrigger": {
            "Type": "CompensationTrigger",
            "Next": "Fail"
        },
        "Succeed": {
            "Type": "Succeed"
        },
        "Fail": {
            "Type": "Fail",
            "ErrorCode": "PURCHASE_FAILED",
            "Message": "purchase failed"
        }
    }
}

测试代码:


 public class LocalSagaTransactionStarter {
        public static void main(String[] args) {
            AbstractApplicationContext applicationContext = new ClassPathXmlApplication
            Context(new String[] {"spring/seata-saga.xml"});
            StateMachineEngine stateMachineEngine = (StateMachineEngine) applicationCon
            text.getBean("stateMachineEngine");
            transactionCommittedDemo(stateMachineEngine);
            transactionCompensatedDemo(stateMachineEngine);
            new ApplicationKeeper(applicationContext).keep();
        }
        private static void transactionCommittedDemo(StateMachineEngine stateMachineEng
ine) {
            Map<String, Object> startParams = new HashMap<>(3);
            String businessKey = String.valueOf(System.currentTimeMillis());
            startParams.put("businessKey", businessKey);
            startParams.put("count", 10);
            startParams.put("amount", new BigDecimal("100"));
//sync test
            StateMachineInstance inst = stateMachineEngine.startWithBusinessKey("reduce
                    InventoryAndBalance", null, businessKey, startParams);
                    Assert.isTrue(ExecutionStatus.SU.equals(inst.getStatus()), "saga transactio
                            n execute failed. XID: " + inst.getId());
            System.out.println("saga transaction commit succeed. XID: " + inst.getId())
            ;
            inst = stateMachineEngine.getStateMachineConfig().getStateLogStore().getSta
            teMachineInstanceByBusinessKey(businessKey, null);
            Assert.isTrue(ExecutionStatus.SU.equals(inst.getStatus()), "saga transactio
                    n execute failed. XID: " + inst.getId());
//async test
            businessKey = String.valueOf(System.currentTimeMillis());
            inst = stateMachineEngine.startWithBusinessKeyAsync("reduceInventoryAndBala
                    nce", null, businessKey, startParams, CALL_BACK);
                    waittingForFinish(inst);
            Assert.isTrue(ExecutionStatus.SU.equals(inst.getStatus()), "saga transactio
                    n execute failed. XID: " + inst.getId());
            分布式事务
            29
            System.out.println("saga transaction commit succeed. XID: " + inst.getId())
            ;
        }
        private static void transactionCompensatedDemo(StateMachineEngine stateMachineE
ngine) {
            Map<String, Object> startParams = new HashMap<>(4);
            String businessKey = String.valueOf(System.currentTimeMillis());
            startParams.put("businessKey", businessKey);
            startParams.put("count", 10);
            startParams.put("amount", new BigDecimal("100"));
            startParams.put("mockReduceBalanceFail", "true");
//sync test
            StateMachineInstance inst = stateMachineEngine.startWithBusinessKey("reduce
                    InventoryAndBalance", null, businessKey, startParams);
//async test
                    businessKey = String.valueOf(System.currentTimeMillis());
            inst = stateMachineEngine.startWithBusinessKeyAsync("reduceInventoryAndBala
                    nce", null, businessKey, startParams, CALL_BACK);
                    waittingForFinish(inst);
            Assert.isTrue(ExecutionStatus.SU.equals(inst.getCompensationStatus()), "sag
                    a transaction compensate failed. XID: " + inst.getId());
            System.out.println("saga transaction compensate succeed. XID: " + inst.getI
                    d());
        }
        private static volatile Object lock = new Object();
        private static AsyncCallback CALL_BACK = new AsyncCallback() {
            @Override
            public void onFinished(ProcessContext context, StateMachineInstance stateMach
ineInstance) {
                synchronized (lock){
                    lock.notifyAll();
                }
            }
            @Override
            public void onError(ProcessContext context, StateMachineInstance stateMachine
Instance, Exception exp) {
                synchronized (lock){
                    lock.notifyAll();
                }
            }
        };
        private static void waittingForFinish(StateMachineInstance inst){

            synchronized (lock){
                if(ExecutionStatus.RU.equals(inst.getStatus())){
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

Seata saga模式

Saga 事务:最终一致性

方案简介

Saga 事务核心思想是将长事务拆分为多个本地短事务,由 Saga 事务协调器协调,如果正常结束那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作

处理流程

Saga事务基本协议
  1. 每个 Saga 事务由一系列幂等的有序子事务(sub-transaction) Ti 组成。
  2. 每个 Ti 都有对应的幂等补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果。
  3. 可以看到,和 TCC 相比,Saga 没有“预留”动作,它的 Ti 就是直接提交到库。

代码实现

// 接⼝略
public class BalanceActionImpl implements BalanceAction {
    private static final Logger LOGGER = LoggerFactory.getLogger(BalanceActionImpl.class);
    @Override
    public boolean reduce(String businessKey, BigDecimal amount, Map<String, Object> params) {
       if(params != null && "true".equals(params.get("throwException"))){
         throw new RuntimeException("reduce balance failed");
       }
       LOGGER.info("reduce balance succeed, amount: " + amount + ", businessKey:" + businessKey);
       return true;
    }
      @Override
      public boolean compensateReduce(String businessKey, Map<String, Object> params) {
            if(params != null && "true".equals(params.get("throwException"))){
                  throw new RuntimeException("compensate reduce balance failed");
            }
            LOGGER.info("compensate reduce balance succeed, businessKey:" + businessKey);
            return true;
      }
}
// 接⼝略
public class InventoryActionImpl implements InventoryAction {
     private static final Logger LOGGER = LoggerFactory.getLogger(InventoryActionImpl.class);
     @Override
     public boolean reduce(String businessKey, int count) {
          LOGGER.info("reduce inventory succeed, count: " + count + ", businessKey:" + businessKey);
          return true;
     }
     @Override
     public boolean compensateReduce(String businessKey) {
          LOGGER.info("compensate reduce inventory succeed, businessKey:" + businessKey);
          return true;
     }
}

Seata XA模式

官⽅⽂档

http://seata.io/zh-cn/docs/dev/mode/xa-mode.html

代码演示

  • 添加Seata的依赖 & 配置
  • 你平时的JDBC代码怎么写,依然怎么写。

4种模式对⽐与选择

AT

优势:
  • 使⽤简单:对业务侵⼊性⼩
缺点:
  • 性能中等
  • 有全局锁
适⽤场景:
  • 适⽤于对性能没有特别⾼的要求的场景
  • 适⽤于不希望对业务进⾏改造的场景

TCC

优势
  • 性能会⽐ AT 模式⾼很多
缺点

相对于 AT 模式,TCC 模式对业务代码有⼀定的侵⼊性

  • 适⽤场景:
    适⽤于核⼼系统等对性能有很⾼要求的场景

Saga

优势:
  • ⼀阶段提交本地数据库事务,⽆锁,⾼性能;
  • 参与者可以采⽤事务驱动异步执⾏,⾼吞吐;
  • 补偿服务即正向服务的“反向”,易于理解,易于实现;
缺点:
  • Saga 模式由于⼀阶段已经提交本地数据库事务,且没有进⾏“预留”动作,所以不能保证隔离性。后续会讲到对于缺乏隔离性的应对措施。
适⽤场景:
  • 业务流程⻓/多
  • 参与者包含其他公司或遗留系统服务,⽆法提供 TCC 模式要求的三个接⼝
  • 典型业务系统:如⾦融⽹络(与外部⾦融机构对接)、互联⽹微贷、渠道整合、分布式架构服务
  • 集成等业务系统
  • 银⾏业⾦融机构使⽤⼴泛

XA

优势:
  • ⽆侵⼊
缺点:
  • 性能较差
  • 需要数据库⽀持XA
适⽤场景:
  • 强⼀致性的解决⽅案,适⽤于对⼀致性要求⾮常⾼的场景(使⽤较少)

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

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

相关文章

TCP通信

目录 一.服务端 1.1创建套接字与绑定 1.2监听 1.3服务端获取连接 1.4服务端提供服务 二.客户端 2.1创建套接字 2.2客户端获取连接 2.3客户端发送需求 三.填充命令行参数 3.1客户端 3.2服务端 3.3结果测试 四.线程版本服务端 4.1线程版 4.2线程池版 一.服务端 与上文…

程序员过圣诞 | 用HTML写出绽放的烟花

文章目录一、前言二、创意名三、效果展示四、烟花代码五、总结一、前言 2022年圣诞节到来啦&#xff0c;圣诞节是基督教纪念耶稣诞生的重要节日。亦称耶稣圣诞节、主降生节&#xff0c;天主教亦称耶稣圣诞瞻礼。耶稣诞生的日期&#xff0c;《圣经》并无记载。公元336年罗马教会…

【博客567】http/2 goaway frame 与 grpc graceful restart

http2 goway frame 与 grpc graceful restart 1、http/2 HTTP/2新增特性 二进制分帧(HTTP Frames)多路复用头部压缩服务端推送(server push)等等新特性 二进制分帧(HTTP Frames)是实现一流多用的基础 HTTP/2最革命性的原因就在于这个二进制分帧了&#xff0c;要了解二进制…

Win10 21H2 19044+vs2019 WDK驱动开发,错误 MSB8040缓解Spectre 漏洞的库以及输出SXS.DLL的垃圾信息

错误 MSB8040缓解Spectre 漏洞的库以及输出SXS.DLL的垃圾信息&#xff0c;win7关闭驱动签名、进入驱动测试模式缓解Spectre 漏洞错误的解决windbg狂刷输出SXS.DLL的垃圾信息的解决缓解Spectre 漏洞错误的解决 在工程配置属性&#xff0c;常规&#xff0c;输出目录&#xff0c;…

SSD_学习笔记记录

one-steage VGG16模型的修改 VGG16的模型输出&#xff0c;其中224.。。为特征图的大小。 SSD模型中对VGG网络的修改&#xff1a; SSD模型是对VGG中的第四个卷积块中的最后一个Conv2d进行第一个输出&#xff0c;在这里简称为Conv4-3。以及第五个卷积块中的最后一个Conv2d进行…

TCP 的可靠传输(计算机网络-运输层)

TCP的可靠传输 因特网的网络层服务是不可靠的 TCP在IP的不可靠的&#xff1a;尽最大努力服务的基础上实现了一种可靠的数据传输服务 TCP采用的可靠传输机制&#xff1a;差错检测、序号、确认、超时重传、滑动窗口等 互联网环境中端到端的时延往往是比较大的&#xff1a;采用…

(机器学习深度学习常用库、框架|Pytorch篇)第二节:Pytorch中数据加载方法(DataLoader、DataSet和Sampler)

文章目录一&#xff1a;DataLoader,、DataSet、Sampler三者的关系二&#xff1a;DataLoader,、DataSet、Sampler详解&#xff08;1&#xff09;DatasetA&#xff1a;基本介绍C&#xff1a;Pytroch内置数据集&#xff08;2&#xff09;SamplerA&#xff1a;SequentialSampler&am…

【算法与数据结构】排序详解(C语言)

目录 前言 插入排序 希尔排序 选择排序 堆排序 冒泡排序 快速排序 hoare版本 ​编辑 挖坑法 前后指针版本 优化 非递归实现 归并排序 非递归实现 前言 &#x1f384;在生活中我们必不可少的就是对一组数据进行排序&#xff0c;所谓排序&#xff0c;就是使一串…

ByteBuffer常用方法与分析

目录 目标 常用API 工具方法 演示案例 allocate(int capacity)和allocateDirect(int capacity) put()和get() flip()和hasRemaining() clear() compact() wrap() 总结 目标 掌握ByteBuffer常用方法&#xff0c;分析ByteBuffer对象在切换读写模式的情况下基本属性的变…

【REDIS】安装配置 可视化工具

Redis作为一个高性能&#xff0c;内存可存储化的no SQL数据库&#xff0c;近两年来发展迅猛&#xff0c;然而并没有比较成熟的管理工具来使用&#xff0c;或者是我不知道 下载redis 并安装&#xff1a; 双击安装&#xff0c;可以安装到d: 盘 配置文件是 .conf Redis作为一个…

排序——快排(递归/非递归)

目录 定义 递归 三种方法 1.hoare法 2.挖坑法 3.双指针法 整体 优化1 优化2 非递归 定义 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&#xff0c;其基本思想为&#xff1a;任取待排序元素序列中 的某元素作为基准值&#xff0c;按照该排序码将待排序集…

快速掌握e语言,以js语言对比,快速了解掌握。

易语言&#xff0c;怎么调试输出&#xff0c;查看内容 在js语言里&#xff0c;弹窗是 alert()在易语言里&#xff0c;弹窗是 信息框 (“弹出显示内容”, 0, “标题”, ); 在js语言里&#xff0c;调试输出是 console.log()在易语言里&#xff0c;调试输出是 调试输出 (“输出内…

开发过程中使用,可以早点下班的coding小技巧

前言 在实际开发过程中,通过时间的沉淀,一些老人常常能写出一些让小白大吃一惊“骚操作”,那些“骚操作”通常简单的离谱,却能做很多事,属实是让很多新人摸不着头脑。 做一件事时间长了,技巧也就有了。 下面来个情景小剧场: 初入职场小鱼仔:这傻逼是不是写错了,~~ s…

基于凸几何和K均值的高光谱端元提取算法(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Sentinel统一异常处理

五.统一异常处理—BlockException 在上述规则测试中&#xff0c;当违反规则时&#xff0c;出来的异常信息页面不够友好和统一&#xff0c;我们可以通过设置统一的异常处理类&#xff0c;针对不同规则显示不同异常信息。 创建一个配置类&#xff0c;实现BlockExceptionHandler…

numpy数组,numpy索引,numpy中nan和常用方法

一&#xff1a;【numpy数组】 1.1为什么要学习numpy 1.快速 2.方便 3.科学计算的基础库 1.2什么是numpy 一个python中做科学计算的基础库&#xff0c;重在数值计算&#xff0c;也是大部分python科学计算库的基础库&#xff0c;多用于在大型&#xff0c;多维数组上执行数组运…

常用的键盘事件

1、键盘事件 键盘事件触发条件onkeyup某个键盘按键被松开时触发onkeydown某个键盘按键被按下时触发onkeypress某个键盘按键被按下时触发&#xff08;但它不识别功能键&#xff0c;比如ctrl、shift等&#xff09; 注意&#xff1a; 如果使用addEventListener不需要加ononkeypr…

Go 堆数据结构使用

说到 container/heap 下的堆数据结构&#xff0c;让我们不需要从零开始实现这个数据结构。如果只是日常工作&#xff0c;其实还挺难用到堆的&#xff0c;更多的还是在写算法题的时候会用到。 基本概念 堆分为大顶堆和小顶堆&#xff0c;区分这两种类型方便我们处理问题。大顶…

Docker安装Zookeeper教程(超详细)

生命无罪&#xff0c;健康万岁&#xff0c;我是laity。 我曾七次鄙视自己的灵魂&#xff1a; 第一次&#xff0c;当它本可进取时&#xff0c;却故作谦卑&#xff1b; 第二次&#xff0c;当它在空虚时&#xff0c;用爱欲来填充&#xff1b; 第三次&#xff0c;在困难和容易之…

第六章:关系数据理论

一、问题的提出、范式 1、【多选题】下列说法中正确的是&#xff1a; 正确答案&#xff1a; ABCD 2、【多选题】关系模式R&#xff08;项目序号&#xff0c;项目代码&#xff0c;项目名称&#xff09;&#xff0c;项目序号是码。一个项目代码只有一个项目名称。下列说法不正确…