Seata分布式事务实战

news2024/11/26 14:56:33

目录

  • 1 Seata
    • 1.1 Seata术语
    • 1.2 Seata AT模式
      • 1.2.1 AT模式及工作流程
      • 1.2.2 Seata-Server安装
      • 1.2.3 集成springcloud-alibaba
    • 1.3 Seata TCC模式
  • 2 Seata注册中心
    • 2.1 服务端注册中心配置
    • 2.2 客户端注册中心配置
  • 3 Seata高可用


1 Seata

在这里插入图片描述
Seata实现分布式事务基础知识:https://blog.csdn.net/ZGL_cyy/article/details/113829282

Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。在 Seata 开源之前,Seata 对应的内部版本在阿里经济体内部一直扮演着分布式一致性中间件的角色,帮助经济体平稳的度过历年的双11,对各BU业务进行了有力的支撑。经过多年沉淀与积累,商业化产品先后在阿里云、金融云进行售卖。2019.1 为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,开放以来,广受欢迎,不到一年已经成为最受欢迎的分布式事务解决方案。

官方中文网:https://seata.io/zh-cn

github项目地址:https://github.com/seata/seata

官方example:https://github.com/seata/seata-samples

1.1 Seata术语

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

在这里插入图片描述

Seata 致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

在这里插入图片描述

1.2 Seata AT模式

​ Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。其中AT模式最受欢迎,使用也非常简单,但它内在的原理不简单。

AT模式的相关资料请参考官方文档说明:https://seata.io/zh-cn/docs/overview/what-is-seata.html

下图是AT模式的执行流程:

在这里插入图片描述

1.2.1 AT模式及工作流程

见官方文档:https://seata.io/zh-cn/docs/overview/what-is-seata.html

1.2.2 Seata-Server安装

我们在选择用Seata版本的时候,可以先参考下官方给出的版本匹配(Seata版本也可以按自己的要求选择):

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

Spring Cloud Alibaba VersionSentinel VersionNacos VersionRocketMQ VersionDubbo VersionSeata Version
2.2.5.RELEASE1.8.01.4.14.4.02.7.81.3.0
2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE1.8.01.3.34.4.02.7.81.3.0
2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE1.7.11.2.14.4.02.7.61.2.0
2.2.0.RELEASE1.7.11.1.44.4.02.7.4.11.0.0
2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE1.7.01.1.44.4.02.7.30.9.0
2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE1.6.31.1.14.4.02.7.30.7.1

我们当前SpringCloud Alibaba的版本是2.2.5.RELEASE,对应Seata版本是1.3.0,所以我们首先安装Seata-Server1.3.0

我们直接基于docker启动得到:

docker run --name seata-server -p 8091:8091 -d -e SEATA_IP=192.168.200.200 -e SEATA_PORT=8091  --restart=on-failure seataio/seata-server:1.3.0

1.2.3 集成springcloud-alibaba

我们接下来开始在项目中集成使用Seata的AT模式实现分布式事务控制,关于如何集成,官方也给出了很多例子,可以通过

https://github.com/seata/seata-samples

在这里插入图片描述

所以各种集成模式需要大家都自行的去翻看对应的samples

集成可以按照如下步骤实现:

1:引入依赖包spring-cloud-starter-alibaba-seata
2:配置Seata
3:创建代理数据源
4:@GlobalTransactional全局事务控制

案例需求:

在这里插入图片描述

如上图,如果用户打车成功,需要修改司机状态、下单、记录支付日志,而每个操作都是调用了不同的服务,比如此时hailtaxi-driver服务执行成功了,但是hailtaxi-order有可能执行失败了,这时候如何实现跨服务事务回滚呢?这就要用到分布式事务。

鉴于我们一般事务都是在service层进行的管理,所以,改造一下hailtaxi-order中的OrderInfoController#add

方法,将业务实现放到对应的Service

/***
     * 下单
     */
/*@PostMapping
    public OrderInfo add(){
        //修改司机信息  司机ID=1
        Driver driver = driverFeign.status("3",2);
        //创建订单
        OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", driver);
        orderInfoService.add(orderInfo);
        return orderInfo;
    }*/

@PostMapping
public OrderInfo add() {
    return orderInfoService.addOrder();
}

Service实现中:

@Service
public class OrderInfoServiceImpl  implements OrderInfoService {
    @Autowired
    private DriverFeign driverFeign;

    /**
     * 1、修改司机信息  司机ID=1
     * 2、创建订单
     * @return
     */
    @Override
    public OrderInfo addOrder() {
        //创建订单
        OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", null);
        int count = orderInfoMapper.add(orderInfo);
        System.out.println("====count="+count);

        //修改司机信息  司机ID=1
        Driver driver = driverFeign.status("1",2);

        orderInfo.setDriver(driver);
        return orderInfo;
    }
}    

案例实现:

0) 创建undo_log

在每个数据库中都需要创建该表:

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

1)依赖引入

我们首先在hailtaxi-driverhailtaxi-order中引入依赖:

<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

2)配置Seata

依赖引入后,我们需要在项目中配置SeataClient 端信息,关于SeataClient端配置信息,官方也给出了很多版本的模板,可以参考官方项目:

https://github.com/seata/seata/tree/1.3.0/script,如下图:

在这里插入图片描述

在这里插入图片描述

我们可以选择spring,把application.yml文件直接拷贝到工程中,文件如下:

在这里插入图片描述

完整文件内容见:https://github.com/seata/seata/blob/1.3.0/script/client/spring/application.yml

修改后我们在hailtaxi-driverhailtaxi-order项目中配置如下:

seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: my_seata_group
  enable-auto-data-source-proxy: true
  use-jdk-proxy: false
  excludes-for-auto-proxying: firstClassNameForExclude,secondClassNameForExclude
  client:
    rm:
      async-commit-buffer-limit: 1000
      report-retry-count: 5
      table-meta-check-enable: false
      report-success-enable: false
      saga-branch-register-enable: false
      lock:
        retry-interval: 10
        retry-times: 30
        retry-policy-branch-rollback-on-conflict: true
    tm:
      degrade-check: false
      degrade-check-period: 2000
      degrade-check-allow-times: 10
      commit-retry-count: 5
      rollback-retry-count: 5
    undo:
      data-validation: true
      log-serialization: jackson
      log-table: undo_log
      only-care-update-columns: true
    log:
      exceptionRate: 100
  service:
    vgroup-mapping:
      my_seata_group: default
    grouplist:
      default: 192.168.200.200:8091
    enable-degrade: false
    disable-global-transaction: false
  transport:
    shutdown:
      wait: 3
    thread-factory:
      boss-thread-prefix: NettyBoss
      worker-thread-prefix: NettyServerNIOWorker
      server-executor-thread-prefix: NettyServerBizHandler
      share-boss-worker: false
      client-selector-thread-prefix: NettyClientSelector
      client-selector-thread-size: 1
      client-worker-thread-prefix: NettyClientWorkerThread
      worker-thread-size: default
      boss-thread-size: 1
    type: TCP
    server: NIO
    heartbeat: true
    serialization: seata
    compressor: none
    enable-client-batch-send-request: true

关于配置文件内容参数比较多,我们需要掌握核心部分:

seata_transaction: default:事务分组,前面的seata_transaction可以自定义,通过事务分组很方便找到集群节点信息。
tx-service-group: seata_transaction:指定应用的事务分组,和上面定义的分组前部分保持一致。
default: 192.168.200.200:8091:服务地址,seata-server服务地址。

注意:

现在配置信息都是托管到nacos中的,所以可以直接将配置存储到nacos中

hailtaxi-order

在这里插入图片描述

hailtaxi-driver

在这里插入图片描述

3)代理数据源

通过代理数据源可以保障事务日志数据和业务数据能同步,关于代理数据源早期需要手动创建,但是随着Seata版本升级,不同版本实现方案不一样了,下面是官方的介绍:

1.1.0: seata-all取消属性配置,改由注解@EnableAutoDataSourceProxy开启,并可选择jdk proxy或者cglib proxy
1.0.0: client.support.spring.datasource.autoproxy=true
0.9.0: support.spring.datasource.autoproxy=true

我们当前的版本是1.3.0,所以我们创建代理数据源只需要在启动类上添加@EnableAutoDataSourceProxy注解即可,

hailtaxi-orderhailtaxi-driver的启动类上分别添加该注解:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.itheima.driver.feign"})
@EnableAutoDataSourceProxy
public class OrderApplication {
}


4)全局事务控制

打车成功创建订单是由客户发起,在hailtaxi-order中执行,并且feign调用hailtaxi-driver,所以hailtaxi-order是全局事务入口,我们在OrderInfoServiceImpl.addOrder()方法上添加@GlobalTransactional,那么此时该方法就是全局事务的入口,

@Override
@GlobalTransactional
public OrderInfo addOrder() {
    //创建订单
        OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", null);
        int count = orderInfoMapper.add(orderInfo);
        //修改司机信息  司机ID=1
        Driver driver = driverFeign.status("1",2);
        orderInfo.setDriver(driver);
        return orderInfo;
}

5)分布式事务测试

1、测试正常情况,启动测试

id=1的司机状态手动改为1,然后进行测试

2、异常测试,在hailtaxi-order的service方法中添加一个异常,

@Override
@GlobalTransactional
public OrderInfo addOrder() {
    //修改司机信息  司机ID=1
    Driver driver = driverFeign.status("1",2);
    //创建订单
    OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", driver);
    int count = orderInfoMapper.add(orderInfo);
    System.out.println("====count="+count);
    //模拟异常
    int i = 1 / 0;
    return orderInfo;
}

测试前,将id=1的司机状态手动改为1,将订单表清空,再次测试,看状态是否被更新,订单有没有添加,以此验证分布式事务是否控制成功!

关于使用feign降级功能导致seata事务无法回滚的问题请看:https://github.com/seata/seata/issues/2088

1.3 Seata TCC模式

一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:

  • 一阶段 prepare 行为
  • 二阶段 commit 或 rollback 行为

在这里插入图片描述

根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction ModeManual (Branch) Transaction Mode.

AT 模式(参考链接 TBD)基于 支持本地 ACID 事务关系型数据库

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。

相应的,TCC 模式,不依赖于底层数据资源的事务支持:

  • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
  • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
  • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

TCC实现原理:

有一个 TCC 拦截器,它会封装 Confirm 和 Cancel 方法作为资源(用于后面 TC 来 commit 或 rollback 操作)
封装完,它会本地缓存到 RM (缓存的是方法的描述信息),可以简单认为是放到一个 Map 里面
当 TC 想调用的时候,就可以从 Map 里找到这个方法,用反射调用就可以了
另外,RM 不光是注册分支事务(分支事务是注册到 TC 里的 GlobalSession 中的)
它还会把刚才封装的资源里的重要属性(事务ID、归属的事务组等)以资源的形式注册到 TC 中的 RpcContext
这样,TC 就知道当前全局事务都有哪些分支事务了(这都是分支事务初始化阶段做的事情)
举个例子:RpcContext里面有资源 123,但是 GlobalSession 里只有分支事务 12
于是 TC 就知道分支事务 3 的资源已经注册进来了,但是分支事务 3 还没注册进来
这时若 TM 告诉 TC 提交或回滚,那 GlobalSession 就会通过 RpcContext 找到 1 和 2 的分支事务的位置(比如该调用哪个方法)
当 RM 收到提交或回滚后,就会通过自己的本地缓存找到对应方法,最后通过反射或其他机制去调用真正的 Confirm 或 Cancel

2 Seata注册中心

参看:https://github.com/seata/seata/tree/1.3.0/script 可以看到seata支持多种注册中心!

2.1 服务端注册中心配置

服务端注册中心(位于seata-server的registry.conf配置文件中的registry.type参数),为了实现seata-server集群高可用不会使用file类型,一般会采用第三方注册中心,例如zookeeper、redis、eureka、nacos等。 我们这里使用nacos,seata-server的registry.conf配置如下:

由于我们是基于docker启动的seata,故可以直接进入到容器内部修改配置文件/resources/registry.conf

registry {
  # file ...nacos ...eureka...redis...zk...consul...etcd3...sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "192.168.200.200:8848"
    group = "SEATA_GROUP"
    namespace = "1ebba5f6-49da-40cc-950b-f75c8f7d07b3"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}

此时我们再重新启动容器,访问:http://192.168.200.200:8848/nacos 看seata是否已注册到nacos中

在这里插入图片描述

2.2 客户端注册中心配置

项目中,我们需要使用注册中心,添加如下配置即可(在nacos配置中心的hailtaxi-order.yamlhailtaxi-driver-dev.yaml都修改)

参看:https://github.com/seata/seata/tree/1.3.0/script

  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 192.168.200.200:8848
      group : "SEATA_GROUP"
      namespace: 1ebba5f6-49da-40cc-950b-f75c8f7d07b3
      username: "nacos"
      password: "nacos"

此时就可以注释掉配置中的default.grouplist="192.168.200.200:8091"

在这里插入图片描述

完整配置如下:

seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: my_test_tx_group
enable-auto-data-source-proxy: true
use-jdk-proxy: false
excludes-for-auto-proxying: firstClassNameForExclude,secondClassNameForExclude
client:
 rm:
   async-commit-buffer-limit: 1000
   report-retry-count: 5
   table-meta-check-enable: false
   report-success-enable: false
   saga-branch-register-enable: false
   lock:
     retry-interval: 10
     retry-times: 30
     retry-policy-branch-rollback-on-conflict: true
 tm:
   degrade-check: false
   degrade-check-period: 2000
   degrade-check-allow-times: 10
   commit-retry-count: 5
   rollback-retry-count: 5
 undo:
   data-validation: true
   log-serialization: jackson
   log-table: undo_log
   only-care-update-columns: true
 log:
   exceptionRate: 100
service:
 vgroup-mapping:
   my_test_tx_group: default
 #grouplist:
   #default: 192.168.200.200:8091
 enable-degrade: false
 disable-global-transaction: false
transport:
 shutdown:
   wait: 3
 thread-factory:
   boss-thread-prefix: NettyBoss
   worker-thread-prefix: NettyServerNIOWorker
   server-executor-thread-prefix: NettyServerBizHandler
   share-boss-worker: false
   client-selector-thread-prefix: NettyClientSelector
   client-selector-thread-size: 1
   client-worker-thread-prefix: NettyClientWorkerThread
   worker-thread-size: default
   boss-thread-size: 1
 type: TCP
 server: NIO
 heartbeat: true
 serialization: seata
 compressor: none
 enable-client-batch-send-request: true
registry:
 type: nacos
 nacos:
   application: seata-server
   server-addr: 192.168.200.200:8848
   group : "SEATA_GROUP"
   namespace: "ce6c9959-8b1d-4596-b15c-22634776af3d"
   username: "nacos"
   password: "nacos"

测试:

启动服务再次测试,查看分布式事务是否仍然能控制住!!!

3 Seata高可用

seata-server 目前使用的是一个单节点,能否抗住高并发是一个值得思考的问题。生产环境项目几乎都需要确保能扛高并发、具备高可用的能力,因此生产环境项目一般都会做集群。

上面配置也只是将注册中心换成了nacos,而且是单机版的,如果要想实现高可用,就得实现集群,集群就需要做一些动作来保证集群节点间的数据同步(会话共享)等操作

我们需要准备2个seata-server节点,并且seata-server的事务日志存储模式,共支持3种方式,

1):file【集群不可用】

2):redis

3):db

我们这里选择redis存储会话信息实现共享。

1、启动第二个seata-server节点

docker run --name seata-server-n2 -p 8092:8092 -d -e SEATA_IP=192.168.200.200 -e SEATA_PORT=8092  --restart=on-failure seataio/seata-server:1.3.0

2、进入容器修改配置文件 registry.conf,添加注册中心的配置

registry {
  # file ...nacos ...eureka...redis...zk...consul...etcd3...sofa
  type = "nacos"

  nacos {
    application = "seata-server"
    serverAddr = "192.168.200.200:8848"
    group = "SEATA_GROUP"
    namespace = "1ebba5f6-49da-40cc-950b-f75c8f7d07b3"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}

3、修改seata-server 事务日志的存储模式,resources/file.conf 改动如下:

我们采用基于redis来存储集群每个节点的事务日志,通过docker运行一个redis

docker run --name redis6.2 --restart=on-failure -p 6379:6379 -d redis:6.2

然后修改seata-server的file.conf,修改如下:

## transaction log store, only used in seata-server
store {
  ## store mode: file...db...redis
  mode = "redis"

  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
    # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "mysql"
    password = "mysql"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

  ## redis store property
  redis {
    host = "192.168.200.200"
    port = "6379"
    password = ""
    database = "0"
    minConn = 1
    maxConn = 10
    queryLimit = 100
  }

}

如果基于DB来存储seata-server的事务日志数据,则需要创建数据库seata,表信息如下:

https://github.com/seata/seata/blob/1.3.0/script/server/db/mysql.sql

修改完后重启

注意:另一个seata-server节点也同样需要修改其存储事务日志的模式

4、再次启动服务测试,查看分布式事务是否依然能控制成功!

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

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

相关文章

“敏捷”又“精益”的新企架思想,如何指导项目实施?

就像“一千个读者眼中有一千个哈姆雷特”&#xff0c;企业也有一千种被看待的方式&#xff0c;例如消费者会用品牌和产品来描述企业&#xff1b;投资者会用盈利模式和盈利空间来评估企业&#xff0c;而“企业架构”则是企业管理者、架构师等用来精确描述企业的方式。 通过业务…

【C语言】语言篇——程序设计入门

C站的小伙伴们大家好呀&#xff01;我最近在学习刘汝佳老师的《算法竞赛入门经典》&#xff0c;跟着这本书来学习和做习题&#xff0c;在这里和大家一起分享进步。下面是本书的第一部分的语言篇。 语言篇——程序设计入门 算术表达式变量及其输入顺序结构程序设计分支结构程序设…

1.1 什么是eBPF?(上)

大多数介绍eBPF的文章都是用“eBPF是一种革命性的内核技术”来描绘的。这样讲一点也不夸张。因为它允许在Linux的内核中执行沙盒程序,在不改变内核源码或加载内核模块的前提下直接地,安全地,快捷地扩展内核,并改变内核的行为。可以想像在运行时,将用户空间的eBPF程序加载到…

C4D R26 渲染学习笔记 建模篇(2):手动建模

介绍篇 C4D R26 渲染学习笔记&#xff08;1&#xff09;&#xff1a;C4D版本选择和初始UI框介绍 C4D R26 渲染学习笔记&#xff08;2&#xff09;&#xff1a;渲染流程介绍 C4D R26 渲染学习笔记&#xff08;3&#xff09;&#xff1a;物体基本操作快捷键 建模篇 C4D R26 渲…

第一个servlet的程序

文章目录 一.Hello World的程序1.创建项目2.引入依赖3.创建目录4.编写代码5.打包程序6.部署程序7.验证程序 二.简化部署方式1.下载插件2.配置smart Tomcat插件3.测试插件 三.常见的servelt问题出现 404出现 405出现 500出现 "空白页面"出现 "无法访问此网站&quo…

图像风格迁移

一、简介 图像风格迁移是指&#xff0c;将一副内容图的内容&#xff0c;和一幅或多幅风格图的风格融合在一起&#xff0c;从而生成一些有意思的图片。 我们使用 TensorFlow 和 Keras 分别来实现图像风格迁移&#xff0c;主要用到深度学习中的卷积神经网络&#xff0c;即CNN。…

Transformer应用之构建聊天机器人(二)

四、模型训练解析 在PyTorch提供的“Chatbot Tutorial”中&#xff0c;关于训练提到了2个小技巧&#xff1a; 使用”teacher forcing”模式&#xff0c;通过设置参数“teacher_forcing_ratio”来决定是否需要使用当前标签词汇来作为decoder的下一个输入&#xff0c;而不是把d…

Linux:查看进程。

Linux&#xff1a;查看进程。 windows linux TTY如果是&#xff1f;说明是不是终端(控制台)启动的&#xff0c;而是系统内部自己启动的。 TIME是启动Linux后&#xff0c;这个进程一共占用了cpu多少时间00…

《Spring Guides系列学习》guide46 - guide50

要想全面快速学习Spring的内容&#xff0c;最好的方法肯定是先去Spring官网去查阅文档&#xff0c;在Spring官网中找到了适合新手了解的官网Guides&#xff0c;一共68篇&#xff0c;打算全部过一遍&#xff0c;能尽量全面的了解Spring框架的每个特性和功能。 接着上篇看过的gui…

《Python安全攻防:渗透测试实战指南》极致经典,学完即可包吃包住

前言 网络江湖&#xff0c;风起云涌&#xff0c;攻防博弈&#xff0c;从未间断&#xff0c;且愈演愈烈。从架构安全到被动纵深防御&#xff0c;再到主动防御、安全智能&#xff0c;直至进攻反制&#xff0c;皆直指安全的本质——攻防。未知攻&#xff0c;焉知防! 每一位网络安…

【Python】循环语句 ② ( while 嵌套循环 | 代码示例 - while 嵌套循环 )

文章目录 一、while 嵌套循环1、while 嵌套循环语法2、代码示例 - while 嵌套循环 一、while 嵌套循环 1、while 嵌套循环语法 while 嵌套循环 就是 在 外层循环 中 , 嵌套 内层循环 ; while 嵌套循环 语法格式 : while 外层循环条件:外层循环操作1外层循环操作2while 内存循…

VuePress + GitHub Actions 自动部署

文章目录 前言背景GitHub Actions简介基本概念引用 Actionworkflow 文件 自动部署创建 Action权限问题 小结参考文献 前言 我的第二本开源书籍《后台开发命令 365》上线啦。 为了方便阅读&#xff0c;使用 VuePress 将之前记录的后台常用 Linux 命令博文整理成一个系统的开源…

路径规划算法:基于阴阳对优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于阴阳对优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于阴阳对优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法…

Compose 没有 inputType 怎么过滤(限制)输入内容?这题我会!

前言 闲话 在我之前的文章 《Compose For Desktop 实践&#xff1a;使用 Compose-jb 做一个时间水印助手》 中&#xff0c;我埋了一个坑&#xff0c;关于在 Compose 中如何过滤 TextField 的输入内容。时隔好几个月了&#xff0c;今天这篇文章就是来填这个坑的。 为什么需要…

Doris

Aggregate 模型 是相同key的数据进行自动聚合的表模型。表中的列按照是否设置了 AggregationType&#xff0c;分为 Key&#xff08;维度列&#xff09;和 Value&#xff08;指标列&#xff09;&#xff0c;没有设置 AggregationType 的称为 Key&#xff0c;设置了 Aggregation…

散列表(哈希表)

目录 散列表 散列函数 散列表常用函数 1. 直接定址法 2. 除留余数法 2.1. exmple 3. 数字分析法 4. 平方取中法 5. 折叠法 处理冲突的方法 1. 开放定址法---线性探测 2. 二次探测法 3. 再Hash法 4. 拉链法(链地址法) 散列表&#xff08;Hash table&#xff0c;也…

Redis缓存击穿及解决问题

缓存击穿的意思是对于设置了过期时间的key,缓存在某个时间点过期的时候&#xff0c;恰好这时间点对这个 Key有大量的并发请求过来&#xff0c;这些请求发现缓存过期- -般都会从后端DB加载数据并回设到缓存&#xff0c;这个时候大并发的请求可能会瞬间把DB压垮。 解决方案有两种…

第五十四天学习记录:C语言进阶:动态内存管理Ⅱ

常见的动态内存错误 1、对NULL指针的解引用操作 int* p(int*)malloc(4); //p进行相关的判断 *p10;//malloc开辟空间失败&#xff0c;有可能对NULL指针解引用 free(p); pNULL;2、对动态开辟的内存的越界访问 int* p(int*)malloc(40);//10个int if(p!NULL) {int i0;//越界for(…

微服务项目租房网

文章目录 一、租房网项目的介绍1、使用的技术介绍2、使用的组件和开发工具的版本以及作用3、项目模块结构4、项目总体架构 二、环境搭建1、启动前端服务2、CentOS7各个组件的安装2.1 安装Docker2.2 安装JDK2.3 安装Redis(6390)2.4 安装FastDFS(8888)2.5 安装MongoDB(27017)2.6 …

Niagara—— 概述

目录 一&#xff0c;核心组件 Systems Emitters Modules Parameters 二&#xff0c;创建系统或发射器向导 System向导 Emetter向导 三&#xff0c;Niagara VFX工作流程 创建系统 创建或添加发射器 创建或添加模块 Niagara是最新一代VFX系统&#xff0c;无需程序员…