分布式事务Seata实践入门

news2024/11/16 14:20:57

1 前言

现在应用基本上都是分布式部署,那么针对分布式事务问题,也有对应的解决方案。经过简单的调研,最后选择了阿里的 Seata 组件,来实现分布式事务。

Seata是2019年1月份,蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,为用户打造一站式的分布式解决方案。

官网地址: http://seata.io/
文档: https://seata.io/zh-cn/docs/overview/what-is-seata.html

2 Seata 模式选择

Seata给我们提供了四种不同的分布式事务解决方案:

  • XA模式
    强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入

  • TCC模式
    最终一致的分阶段事务模式,有业务侵入

  • AT模式
    最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式

  • SAGA模式
    长事务模式,有业务侵入

综合业务量,可用性,以及集成的成本,最终选择了无业务入侵的 AT模式。

基于现有的Spring Boot版本,Spring Cloud版本,Spring Cloud Alibaba版本以及Mybatis Plus动态数据源版本,最后选择seata的1.5.2版本。

Spring Version5.2.15.RELEASE
Spring Boot Version2.3.12.RELEASE
Spring Cloud VersionHoxton.SR12
Spring Cloud Alibaba Version2.2.9.RELEASE

3 Seata Server端搭建

Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TMRM(Client端)由业务系统集成。

笔者采用file作为服务的注册中心,数据存储采用的db,数据源采用的hikari

3.1 下载Server源码包

seata-server-1.5.2.zip

可以使用本地部署,也可以使用 Docker部署(忽略该步骤)

3.2 建表

全局事务会话信息由3块内容构成,全局事务–>分支事务–>全局锁,对应表global_tablebranch_tablelock_table

创建seata数据库,注意:表结构字符集,需调整为 utf8mb4

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`),
    KEY `idx_xid_and_branch_id` (`xid` , `branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);

3.3 Server配置

完整的配置实例如下:

server:
  port: 6689

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
#  extend:
#    logstash-appender:
#      destination: 127.0.0.1:4560
#    kafka-appender:
#      bootstrap-servers: 127.0.0.1:9092
#      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos 、 consul 、 apollo 、 zk  、 etcd3
    type: file
  registry:
    # support: nacos 、 eureka 、 redis 、 zk  、 consul 、 etcd3 、 sofa
    type: file
    # file field
    preferred-networks: 30.240.*
  server:
    #If not configured, the default is '${server.port} + 1000'
    #service-port: 8091
    max-commit-retry-timeout: -1
    max-rollback-retry-timeout: -1
    rollback-retry-timeout-unlock-enable: false
    enable-check-auth: true
    enable-parallel-request-handle: true
    retry-dead-threshold: 130000
    xaer-nota-retry-timeout: 60000
    recovery:
      handle-all-session-period: 1000
    undo:
      log-save-days: 7
      log-delete-period: 86400000
    session:
      #branch async remove queue size
      branch-async-queue-size: 5000
      #enable to asynchronous remove branchSession
      enable-branch-async-remove: false
  store:
    # support: file 、 db 、 redis
    mode: db
    session:
      mode: db
    lock:
      mode: db
    #io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 8388608: 1345270062 - discarded
    file:
      dir: sessionStore
      max-branch-session-size: 16384
      max-global-session-size: 512
      file-write-buffer-cache-size: 16384
      session-reload-read-size: 100
      flush-disk-mode: async
    db:
      branchTable: branch_table
      # hikari or druid
      datasource: hikari
      dbType: mysql
      distributedLockTable: distributed_lock
      globalTable: global_table
      lockTable: lock_table
      maxConn: 30
      maxWait: 5000
      minConn: 5
      queryLimit: 100
      driverClassName: com.mysql.cj.jdbc.Driver
      url: xxx/seata?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true
      user: xxx
      password: xxx

  metrics:
    enabled: false
    registry-type: compact
    exporter-list: prometheus
    exporter-prometheus-port: 9898
  transport:
    rpc-tc-request-timeout: 30000
    enable-tc-server-batch-send-response: false
    shutdown:
      wait: 3
    thread-factory:
      boss-thread-prefix: NettyBoss
      worker-thread-prefix: NettyServerNIOWorker
      boss-thread-size: 1
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf5335jlkjlj53454j4jfdjfggj
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

3.4 启动Seata Server

seata-server.sh 脚本启动即可,启动成功如下:
在这里插入图片描述

4 Seata Client 集成

在需要使用分布式事务的服务中,都需要如下操作,注意:只有主入口需要@GlobalTransactional注解

4.1 添加undo_log回滚记录表

所有的客户端,都需要添加该表,另外,回滚操作成功后,该表会被清空,所以每次看都是空的

CREATE TABLE `undo_log`
(
    `branch_id`     bigint(20)   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
  DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';

4.2 添加依赖

<!--seata client config-->
    <dependency>
          <groupId>io.seata</groupId>
          <artifactId>seata-spring-boot-starter</artifactId>
          <version>1.5.2</version>
          <exclusions>
              <exclusion>
                  <groupId>com.alibaba</groupId>
                  <artifactId>druid</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
          <version>2.2.9.RELEASE</version>
          <exclusions>
              <exclusion>
                  <groupId>io.seata</groupId>
                  <artifactId>seata-spring-boot-starter</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
          <version>3.4.1</version>
      </dependency>

4.3 Seata Client config

关于事务分组,详细请参考:https://seata.io/zh-cn/docs/user/txgroup/transaction-group.html

server:
  port: 6687

spring:
  datasource:
    dynamic:
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: master
      # 严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
      # 默认false非懒启动,系统加载到数据源立即初始化连接池
      lazy: false
      #开启seata代理,开启后默认每个数据源都代理,如果某个数据源不需要代理可单独关闭
      seata: true
      #支持XA及AT模式,默认AT
      seata-mode: AT
      # 全局hikariCP参数,所有值和默认保持一致(现已支持的参数如下)
      hikari:
        catalog:
        # 数据库连接超时时间,默认60秒,即 60000
        connection-timeout: 60000
        validation-timeout:
        #空闲连接存活最大时间,默认 600000(10分钟)
        idle-timeout: 600000
        leak-detection-threshold:
        max-lifetime:
        #连接池最大连接数,默认是10
        max-pool-size: 10
        #最小空闲连接数量
        min-idle: 10
        initialization-fail-timeout:
        connection-init-sql:
        connection-test-query:
        dataSource-class-name:
        dataSource-jndi-name:
        schema:
        transaction-isolation-name:
        # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
        is-auto-commit: true
        is-read-only: false
        is-isolate-internal-queries:
        is-register-mbeans:
        is-allow-pool-suspension:
        data-source-properties:
        health-check-properties:
      datasource:
        master:
          seata: false
          type: com.zaxxer.hikari.HikariDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: xxx?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true
          username: xxx
          password: xxx
        order:
          type: com.zaxxer.hikari.HikariDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: xxx/seata_order?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true
          username: xxx
          password: xxx
        account:
          type: com.zaxxer.hikari.HikariDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: xxx/seata_account?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true
          username: xxx
          password: xxx
        product:
          type: com.zaxxer.hikari.HikariDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: xxx/seata_product?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&allowMultiQueries=true
          username: xxx
          password: xxx


seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: smile_tx_group
  #一定要是false,组件内部开启seata后会自动使用DataSourceProxy来包装DataSource
  enable-auto-data-source-proxy: false
  service:
    vgroup-mapping:
      # Transaction routing rules configuration, only for the client,The key corresponds to the value of tx service group above
      # Specify the transaction grouping to cluster mapping relationship (the cluster name on the right side of the equal sign needs to be consistent with the cluster registered by Seata Server)
      smile_tx_group: default
    grouplist:
      #seata-server地址仅file注册中心需要(这里要与server监听的端口一致)
      default: 127.0.0.1:7689
  config:
    type: file
  registry:
    type: file
  client:
    rm:
      # 1.5.2版本仅支持druid和antlr,这里虽然使用了hikari数据源,解析sql使用的druid,不冲突也不影响结果,详情可参考源码:io.seata.sqlparser.SqlParserType
      sqlParserType: druid

5 代码实践

这里采用常见的示例举例

5.1 正常下单

服务A代码示例:

/**
     * 正常下单
     */
    @PostMapping("/placeOrder")
    public String placeOrder(@Validated @RequestBody PlaceOrderRequest request) {
        orderService.placeOrder(request);
        return "下单成功";
    }

/**
     * 下单
     *
     * @param placeOrderRequest 订单请求参数
     */
    void placeOrder(PlaceOrderRequest placeOrderRequest);

	@DS("order")
    @Override
    @Transactional
    @GlobalTransactional
    @SuppressWarnings("all")
    public void placeOrder(PlaceOrderRequest request) {
    	log.info("当前的XID为: {}", RootContext.getXID());
        //业务执行省略。。。
    }

5.2 下单业务异常,事务回滚

服务A代码示例:

/**
     * 下单-添加操作日志失败回滚
     */
    @PostMapping("/placeOrderFail")
    public String placeOrderFail(@Validated @RequestBody PlaceOrderRequest request) {
        orderService.placeOrderFail(request);
        return "下单成功,操作日志记录失败回滚";
    }

/**
     * <p>
     * place order fail
     * <p/>
     *
     * @param placeOrderRequest
     * @return void
     * @Date 2023/4/15 14:22
     */
    void placeOrderFail(PlaceOrderRequest placeOrderRequest);
	
	/**
     * <p>
     * place order fail
     * <p/>
     *
     * @param placeOrderRequest
     * @return void
     * @Date 2023/4/15 14:22
     */
    @DS("order")
    @Override
    @Transactional
    @GlobalTransactional
    @SuppressWarnings("all")
    public void placeOrderFail(PlaceOrderRequest request) {
        log.info("placeOrderFail xid: {}", RootContext.getXID());
		//下单、减库存、处理账户余额
        this.placeOrder(request);

        ApiLogger apiLogger = new ApiLogger();
        apiLogger.setUserId(request.getUserId());
        apiLogger.setBizId(String.valueOf(request.getUserId() + new Random().nextInt(100)));
        //场景一:另一个分布式服务,执行业务异常(下游分布式服务报错,导致上游所有服务回滚)
        feignClient.insertApiLoggerInfo(apiLogger);
		
		//场景二:当前业务执行异常,回滚本事务,同时回滚另一个feignClient分布式事务(上游报错,导致下游事务回滚)
        int i = 1 / 0;
    }

另一个分布式服务B代码示例:

	@Transactional(propagation = Propagation.REQUIRES_NEW)
    @PostMapping("/insert")
    public ObjectRestResponse<String> insertApiLoggerInfo(@RequestBody ApiLogger apiLogger) {
        log.info("insertApiLoggerInfo xid: {}", RootContext.getXID());
        apiLoggerService.save(apiLogger);
        //int i = 1 / 0;
        return ObjectRestResponse.success("insert api logger info success");
    }

5.3 启动Seata Client

启动分布式服务即可,出现以下内容,说明客户端启动成功

在这里插入图片描述

回滚成功时,可以看到以下内容:
在这里插入图片描述

6 踩坑总结

分布式事务组件,其实国内稳定的版本还不是很多,能业务自己实现最终一致性最好,否则才考虑使用Seata组件。笔者踩了好多坑,这里记录下最大的坑

  • 报错1:
    ### SQL: INSERT INTO p_order ( user_id, product_id, status, amount ) VALUES ( ?, ?, ?, ? )### Cause: java.sql.SQLException: io.seata.common.loader.EnhancedServiceNotFoundException: not found service provider for : io.seata.rm.datasource.sql.struct.TableMetaCache ; uncategorized SQLException; SQL state [null]; error code [0]; io.seata.common.loader.EnhancedServiceNotFoundException: not found service provider for : io.seata.rm.datasource.sql.struct.TableMetaCache; nested exception is java.sql.SQLException: io.seata.common.loader.EnhancedServiceNotFoundException: not found service provider for : io.seata.rm.datasource.sql.struct.TableMetaCache

    io.seata.rm.datasource.sql.struct.TableMetaCache这个错误,太容易出现了,看了好多的issue,最终都没有解决,最后只能看源码
    在这里插入图片描述
    在这里插入图片描述
    这里list集合判空,不是很严谨,本来应该加载资源,最后没加载,导致报错。

    当然,这个是访问时报的错,其实,在启动类的时候也会加载一次,所以整体上不会出问题的,出问题了,说明大概是jar版本依赖不兼容导致的。

  • 报错2
    io.seata.rm.datasource.sql.struct.cache.MysqlTableMetaCache java.lang.NoClassDefFoundError: io.seata.rm.datasource.sql.struct.cache.AbstractTableMetaCache ServiceLoader$InnerEnhancedServiceLoader : Load [io.seata.rm.datasource.sql.struct.cache.MysqlTableMetaCache] class fail. com/github/benmanes/caffeine/cache/Caffeine has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

    当出现java.lang.NoClassDefFoundError时,应该第一想到是不是跟其他组件版本不兼容,笔者的是跟一个缓存的组件caffeine产生了问题,根据github官网的描述,对于jdk11 以上的jdk版本请使用3.1.x,否则使用2.9.x,For Java 11 or above, use 3.1.x otherwise use 2.9.x,将基础组件的版本,从3.0.0降到了2.9.3,该问题得到了解决

基础入门实践,就先写到这里,后面再简单分享下原理,以及把注册的方式,由file升级为nacos形式,敬请期待~

写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,希望尽自己的努力,做到更好,大家一起努力进步!

如果有什么问题,欢迎大家一起探讨,代码如有问题,欢迎各位大神指正!

给自己的梦想添加一双翅膀,让它可以在天空中自由自在的飞翔!

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

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

相关文章

(TinkSystem SR650)安装服务器操作系统(Windows Server 2022)步骤和相关概念

&#xff08;TinkSystem SR650&#xff09;安装服务器操作系统&#xff08;Windows Server 2022&#xff09;步骤和相关概念 服务器操作系统安装步骤 记录一下服务器操作系统安装过程&#xff0c;虽然简单但还是有一些坑需要注意&#xff0c;本次使用的是联想服务器ThinkSyst…

VS2019中Ctrl+左键不起作用和控制台不驻留(cmd窗口闪退)

1、关于Ctrl左键不起作用 解决&#xff1a;在线装个插件就行。 工具>>扩展和更新 联机>>VS库>>所搜插件“GO TO Definition” 安装&#xff0c;重启VS即可。 2、关于控制台不驻留 当然这个问题解决方案有很多&#xff0c;这个是首选吧

[Java·算法·中等]LeetCode105. 从前序与中序遍历序列构造二叉树

每天一题&#xff0c;防止痴呆 前言题目示例分析思路1题解1分析思路2题解2 &#x1f449;️ 力扣原文 前言 二叉树前序遍历的顺序为&#xff1a; 先遍历根节点&#xff1b; 随后递归地遍历左子树&#xff1b; 最后递归地遍历右子树。 二叉树中序遍历的顺序为&#xff1a; 先递…

HCIP-6.9BGP路由反射器原理与配置

路由反射器原理与配置 1、路由反射器概念1.1、路由反射器原理&#xff1a;1.2、多集群路由反射器1.3、备份路由反射器2、路由反射器配置3、路由反射器防环机制 1、路由反射器概念 IBGP的水平分割&#xff0c;IBGP 1只能update一跳&#xff0c;就是说在IBGP 2 设备收到IBGP 1设…

【RocketMQ】事务的实现原理

事务的使用 RocketMQ事务的使用场景 单体架构下的事务 在单体系统的开发过程中&#xff0c;假如某个场景下需要对数据库的多张表进行操作&#xff0c;为了保证数据的一致性&#xff0c;一般会使用事务&#xff0c;将所有的操作全部提交或者在出错的时候全部回滚。以创建订单…

12-RabbitMQ

一 RabbitMQ概念 1 MQ 消息队列 MQ全称Message Queue&#xff08;消息队列&#xff09;&#xff0c;是在消息的传输过程中保存消息的容器。多用于系统之间的异步通信。 同步通信相当于两个人当面对话&#xff0c;你一言我一语。必须及时回复 异步通信相当于通过第三方转述对…

ObjectBox一种基于中心点的无锚点目标检测方法

ObjectBox: From Centers to Boxes for Anchor-Free Object Detection 论文地址&#xff1a;https://arxiv.org/pdf/2207.06985.pdf 官方代码&#xff1a;https://github.com/MohsenZand/ObjectBox 基于中心点的无锚点目标检测方法是一种目标检测方法&#xff0c;其思路是将目…

DJ编曲用什么软件,DJ编曲教需要哪些步骤

随着现在人们的生活水平不断提高&#xff0c;我们的精神生活也越来越丰富&#xff0c;对于现在的年轻人来说&#xff0c;DJ舞曲是一个较受欢迎的领域&#xff0c;有许多年轻人对DJ这个职业感兴趣&#xff0c;想要深入了解DJ编曲这份工作&#xff0c;那么今天我们就来说一说DJ编…

300元买什么蓝牙耳机性价比高?300左右性价比高的蓝牙耳机推荐

TWS耳机已经成了很多人生活的必需品&#xff0c;如今的耳机在设计、功能、体验等方面都非常完善&#xff0c;拥有一副TWS耳机似乎已经成为时尚的标志&#xff0c;尤其是年轻群体&#xff0c;耳机既是听歌、娱乐的主力设备&#xff0c;也是穿搭风格、个性的体现&#xff0c;下面…

JDBC事务 Hibernate事务 EJB事务详解

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;JDBC事务 Hibernate事务 EJB事务详解 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你…

【学习笔记】Integral Human Pose Regression

【学习资料】一文总结Integral Pose Regression方法的方方面面 - 知乎&#xff08;总结的很到位&#xff0c;一定要去看&#xff09; 1.两种基本方法的对比 1.解码方式 softmax和argmax的区别&#xff1a; 由于深度神经网络中的下采样步骤&#xff0c;热图的分辨率低于输入…

如何在电脑本地下载镜像重装系统

现在网上随处可以下载操作系统&#xff0c;下载下来的是镜像系统&#xff0c;很多朋友都不知道电脑镜像重装系统是什么意思&#xff0c;怎么用镜像重装系统&#xff0c;今天小编就给大家带来了电脑镜像重装系统是什么意思的相关解答&#xff0c;一起往下看。 电脑镜像重装系统是…

从FPGA说起的深度学习(七)-循环并行化

这是新的系列教程&#xff0c;在本教程中&#xff0c;我们将介绍使用 FPGA 实现深度学习的技术&#xff0c;深度学习是近年来人工智能领域的热门话题。在本教程中&#xff0c;旨在加深对深度学习和 FPGA 的理解。用 C/C 编写深度学习推理代码高级综合 (HLS) 将 C/C 代码转换为硬…

不良事件上报系统源码开发,不良事件上报系统源码

不良事件管理系统源码&#xff0c;有演示&#xff0c;支持二开&#xff0c;可正常上线运营。 相关技术&#xff1a;PHPvscodevue2elementlaravel8mysql5.7 文末获取联系&#xff01; 医院安全不良事件上报系统&#xff0c;对患者安全&#xff08;不良&#xff09;事件实施全过…

微分方程的基本概念(通解、特解,线素场)

微分方程的基本概念(通解、特解&#xff0c;线素场)1 微分方程的定义 同学们大家好&#xff0c;今天我们来学习微分方程的基础概念。 微分方程就是含有导数的方程&#xff0c;例如&#xff1a; 它就含有导数 &#xff0c;因此它就是一个微分方程。而我们知道导数的写法不止一…

androidstudio虚拟机运行react-native项目踩坑指南

androidstudio虚拟机运行react-native项目踩坑指南安装JDK安装android studio配置环境变量新建虚拟机新建RN项目运行项目本文详细的记录了照react-native官网文档运行项目踩到的所有坑&#xff0c;诚然&#xff0c;官网只介绍了每一步&#xff0c;最后确实是可以正常运行项目&a…

VS2022配置Opencv贴心教程

所用VS2022是官网Professional版本&#xff0c;OpenCV版本是4.7.0 一、下载OpenCV 官网下载地址&#xff1a;Releases - OpenCV 选择Windows版本下载并解压到本地磁盘&#xff0c;建议路径不带中文&#xff0c;我的解压安装地址是&#xff1a; C:\opencv 二、配置Windows环…

快速部署个人-ChatGPT Next Web

前提&#xff1a;要有梯子、谷歌账号。 目录 一、源码地址&#xff1a; 二、演示地址&#xff1a; 三、获取API密钥 四、 部署 五、重新部署 一、源码地址&#xff1a; GitHub - Yidadaa/ChatGPT-Next-Web: One-Click to deploy well-designed ChatGPT web UI on Verc…

1.Shell编程自动化之Shell编程基础

一、Shell可以用来做什么 1.自动化批量系统初始化程序&#xff1b; 2.自动化批量软件部署程序&#xff1b; 3.应用程序管理&#xff1b; 4.日志分析处理程序&#xff1b; 5.自动化备份恢复程序&#xff1b; 6.自动化信息采集及监控程序&#xff1b; 7.自动化管理程序&am…

Python数据结构-----leetcode232.用栈实现队列

目录 前言&#xff1a; 方法讲解 示例&#xff1a; 代码实现 232. 用栈实现队列 前言&#xff1a; 我们都知道队列的特征是先进先出&#xff0c;就跟排队一样先到先得&#xff0c;而栈的特征是后进后出&#xff0c;那这里我们怎么去通过两个栈来实现一个队列的功能呢&#xf…