【Spring Cloud】Spring Cloud Alibaba-- 分布式事务Seata原理

news2024/10/5 15:24:42

文章目录

  • 前言
  • 一、Seata 介绍
    • 1.1、Seata 简介
    • 1.2、Seata 的核心组件
    • 1.3、Seata 的整体执行流程
  • 二、Seata 的 AT 模式原理
    • 2.1、AT 模式的整体执行流程
    • 2.2、AT 模式两阶段详细流程
      • 2.2.1、第一阶段的详细执行流程
      • 2.2.2、第二阶段提交的详细执行流程
      • 2.2.3、第二阶段回滚的详细执行流程
  • 三、Seata 的 TCC、Saga、XA模式原理
    • 3.1、TCC 模式
    • 3.2、Saga 模式
    • 3.3、XA模式
  • 四、SpringCloud Alibaba 整合 Seata AT 模式
    • 4.1、搭建 Seata TC 协调者
      • 4.1.1、下载 Seata TC 协调者
      • 4.1.2、创建TC所需要的表
      • 4.1.3、修改TC的注册中心和配置中心
      • 4.1.4、导入 seata Server 配置
      • 4.1.5、修改TC的事务信息存储方式
      • 4.1.6、启动TC
    • 4.2、搭建Seata 客户端(RM)
      • 4.2.1、maven 添加 seata 依赖
      • 4.2.2、application.yml 添加 seate 配置
      • 4.2.3、数据库中添加回滚日志表
      • 4.2.4、使用 seata 作为全局事务控制
      • 4.2.5、undo log 表介绍

前言

一、Seata 介绍

1.1、Seata 简介

Seata 是一款开源的分布式事务解决方案,致力于提供高性能与简单易用的分布式事务服务,为用户提供了 AT、TCC、SAGA 和 XA 几种不同的事务模式:

  • AT模式:无侵入式的分布式事务解决方案,适合不希望对业务进行改造的场景,但由于需要添加全局事务锁,对影响高并发系统的性能。该模式主要关注多DB访问的数据一致性,也包括多服务下的多DB数据访问一致性问题
  • TCC模式:高性能的分布式事务解决方案,适用于对性能要求比较高的场景。该模式主要关注业务拆分,在按照业务横向扩展资源时,解决服务间调用的一致性问题
  • Saga模式:长事务的分布式事务解决方案,适用于业务流程长且需要保证事务最终一致性的业务系统。Saga 模式一阶段就会提交本地事务,无锁,长流程情况下可以保证性能,多用于渠道层、集成层业务系统,事务参与者可以是其它公司的服务也可以是遗留系统的服务,并且对于无法进行改造和提供 TCC 要求的接口,也可以使用 Saga 模式

1.2、Seata 的核心组件

在 Seata 中主要有以下三种角色,其中 TM 和 RM 是作为 Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署:

  • 事务协调器(TC):维护全局事务的运行状态,负责协调并驱动全局提交或回滚
  • 事务管理器(TM):事务发起方,控制全局事务的范围,负责开启一个全局事务,并最终发起全局提交或回滚全局的决议
  • 资源管理器(RM):事务参与方,管理本地事务正在处理的资源,负责向 TC 注册本地事务、汇报本地事务状态,接收 TC 的命令来驱动本地事务的提交或回滚

1.3、Seata 的整体执行流程

在这里插入图片描述

Seata 分布式事务的整体执行机制如上图所示,可以大致分为两阶段提交:

  1. 发起方 TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成唯一的全局事务标识 XID,该 XID 在后续事务的服务调用链路的上下文传播(通过Aop实现))
  2. RM 向 TC 注册分支事务,汇报资源准备状况,并与 XID 进行绑定(Branch分支事务指分布式事务中每个独立的本地局部事务)
  3. TM 向 TC 发起 XID 下的所有分支事务的全局提交或回滚请求(事务一阶段结束)
  4. TC 汇总事务信息,决定分布式事务是提交还是回滚;
  5. TC 通知所有 RM 提交/回滚 资源,事务二阶段结束;

二、Seata 的 AT 模式原理

Seata AT模式是基于XA事务(XA是基于数据库实现的分布式事务协议)演进而来,需要数据库支持,如果是 MySQL,则需要5.6以上版本才支持XA协议。AT 模式的特点就是对业务无入侵式,用户只需要关注自己的业务SQL,Seata 框架会在第一阶段拦截并解析用户的 SQL,并保存其变更前后的数据镜像,形成undo log,并自动生成事务第二阶段的提交和回滚操作。

2.1、AT 模式的整体执行流程

在这里插入图片描述

AT 模式 RM 驱动分支事务的行为分为以下两个阶段:

  1. 执行阶段:

    • 代理 JDBC 数据源,拦截并解析业务 SQL,生成更新前后的镜像数据,形成 UNDO LOG。
    • 向 TC 注册分支。
    • 分支注册成功后,把业务数据的更新和 UNDO LOG 放在同一个本地事务中提交。
  2. 完成阶段:

    • 全局提交,收到 TC 的分支提交请求,异步删除相应分支的 UNDO LOG。
    • 全局回滚,收到 TC 的分支回滚请求,查询分支对应的 UNDO LOG 记录,生成补偿回滚的 SQL 语句,执行分支回滚并返回结果给 TC

2.2、AT 模式两阶段详细流程

2.2.1、第一阶段的详细执行流程

在这里插入图片描述

在第一阶段,RM 写表时,Seata 通过代理数据源(从而达到对业务无侵入的效果)拦截业务 SQL 并 解析 SQL 语义,找到该 SQL 要更新的业务数据保存成 before image(前置镜像),然后执行业务SQL,在业务数据更新后,再将其保存成 after image(后置镜像),最后生成行锁。通过把更新前后的业务数据数据镜像组织成回滚日志 undo log,并利用本地事务的 ACID 特性,将业务数据的更新和回滚日志 undo log 的写入在同一个本地事务中提交,保证任何提交的业务数据的更新一定有相应的回滚日志存在(即操作的原子性)。

基于这样的机制,分支的本地事务就可以在全局事务的第一阶段提交,并马上释放本地事务锁定的资源,这也是 Seata 的 AT 模式和 XA 事务的不同之处,两阶段提交往往对资源的锁定需要持续到第二阶段实际的提交或者回滚操作,而有了回滚日志之后,可以在第一阶段释放对资源的锁定,降低了锁范围,提高效率,即使第二阶段发生异常需要回滚,只需找对 undo log 中对应数据镜像并反解析成 SQL 来达到回滚目的

2.2.2、第二阶段提交的详细执行流程

在这里插入图片描述

如果二阶段的全局表决结果是提交的话,说明所有分支事务的业务SQL已经在第一阶段生效,此时 Seata 框架只需异步删除所有分支第一阶段保存的镜像数据、回滚日志和行锁,完成数据清理即可,这个过程是非常快速的

2.2.3、第二阶段回滚的详细执行流程

在这里插入图片描述

如果第二阶段是回滚的话,Seata 就需要回滚第一阶段已执行的 SQL 进行还原业务数据。由 TC 通知所有 RM 进行根据第一阶段的回滚日志 undo log (即before image)进行反向补偿,RM 收到 TC 发来的回滚请求后,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过undo log 生成反向的更新 SQL 并执行,以完成分支的业务数据还原,最后删除 undo log、redo log 和行锁。但在还原前需要校验脏写,对比数据库”当前业务数据”和 “after image”,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理。

三、Seata 的 TCC、Saga、XA模式原理

    文章第二部分介绍了 Seata 的 AT 模式,接下来我们就介绍下 Seata 的其实几种事务模式:

3.1、TCC 模式

在这里插入图片描述

TCC 模式 RM 驱动分支事务的行为分为以下两个阶段:

  1. 执行阶段:

    ① 向 TC 注册分支。
    ② 执行业务定义的 Try 方法。
    ③ 向 TC 上报 Try 方法执行情况:成功或失败。

  2. 完成阶段:

    ① 全局提交,收到 TC 的分支提交请求,执行业务定义的 Confirm 方法。
    ② 全局回滚,收到 TC 的分支回滚请求,执行业务定义的 Cancel 方法。

3.2、Saga 模式

在这里插入图片描述

Saga 模式 RM 驱动分支事务的行为包含以下两个阶段:

  1. 执行阶段:

    ① 向 TC 注册分支。
    ② 执行业务方法。
    ③ 向 TC 上报业务方法执行情况:成功或失败。

  2. 完成阶段:

    全局提交,RM 不需要处理。
    全局回滚,收到 TC 的分支回滚请求,执行业务定义的补偿回滚方法。

3.3、XA模式

在这里插入图片描述

XA 模式 RM 驱动分支事务的行为包含以下两个阶段:

  1. 执行阶段:

    ① 向 TC 注册分支
    ② XA Start,执行业务 SQL,XA End
    ③ XA prepare,并向 TC 上报 XA 分支的执行情况:成功或失败

  2. 完成阶段:

    收到 TC 的分支提交请求,XA Commit
    收到 TC 的分支回滚请求,XA Rollback

参考文章:

https://help.aliyun.com/document_detail/157850.html

四、SpringCloud Alibaba 整合 Seata AT 模式

4.1、搭建 Seata TC 协调者

4.1.1、下载 Seata TC 协调者

Seata 的协调者其实就是阿里开源的一个服务,我们只需要下载(下载地址:https://github.com/seata/seata/releases)并启动它,下载完成后,直接解压即可,但是此时还不能直接运行,还需要做一些配置

在这里插入图片描述

4.1.2、创建TC所需要的表

https://github.com/seata/seata/tree/1.4.2/script/server/db

TC 运行需要将事务信息保存在数据库,因此需要创建一些表,找到 seata-1.4.2 源码的 script\server\db 这个目录,将会看到以下SQL文件:

在这里插入图片描述

以 MySQL 数据库为例,创建数据库 seata,并执行 mysql.sql 文件中的sql语句:

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_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
 
-- 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 = utf8;
 
-- 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),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

创建的三张表如下图:

在这里插入图片描述

  • global_table:全局事务表,每当有一个全局事务发起后,就会在该表中记录全局事务的ID
  • branch_table:分支事务表,记录每一个分支事务的ID,分支事务操作的哪个数据库等信息
  • lock_table:全局锁

4.1.3、修改TC的注册中心和配置中心

找到 seata-server-1.4.2\seata\conf 目录,其中有一个 registry.conf 文件,其中配置了TC的注册中心和配置中心。默认的注册中心是 file 形式,实际使用中肯定不能使用,需要改成Nacos形式;同样 Seate 的 TC 的配置中心默认也是使用 file 形式,需要修改为 nacos 作为配置中心:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  nacos {
    application = "seata-server"
    serverAddr = "localhost:8848"
    namespace = "XXXXXXXXXX"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}


 
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"
  nacos {
    serverAddr = "localhost:8848"
    namespace = "XXXXXXXXXX"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

需要改动的地方如下:

  • type:改成nacos,表示使用nacos作为注册中心或者配置中心
  • application:服务的名称
  • serverAddr:nacos的地址
  • group:分组
  • namespace:命名空间
  • username:用户名
  • password:密码
    上述配置修改好之后,在TC启动的时候将会自动读取 nacos 的配置,最后这份 registry.conf 文件的配置需要与下文每个seata客户端项目中的配置一致

4.1.4、导入 seata Server 配置

建议将 seata 项目下载到本地并阅读 https://github.com/seata/seata/tree/1.4.2/script/config-center 路径下的README.md内容

在上面我们已经配置好 seata TC 的配置中心,那么 TC 需要存储到 Nacos 的配置都有哪些,如何推送过去呢?在 https://github.com/seata/seata/tree/1.4.2/script/config-center 中有一个 confIg.txt 文件,其中就是 TC 需要的全部配置,而 https://github.com/seata/seata/tree/1.4.2/script/config-center/nacos 中有一个 nacos-config.sh 脚本能够将 config.txt 中的全部配置自动推送到nacos中。

我们先启动nacos服务,然后在 nacos-config.sh 目录下执行下面命令,将 config.txt 中的配置信息推送到 nacos 中:

# -h 代表nacos服务的IP;-p 代表nacos的端口号;-g 分组信息;-t 命名空间ID;-u 用户名,-p 密码
$ sh nacos-config.sh -h 127.0.0.1 -p 8080 -g SEATA_GROUP -t 7a7581ef-433d-46f3-93f9-5fdc18239c65 -u nacos -w nacos

命令执行成功后,就可以在nacos中看到如下配置:

在这里插入图片描述

4.1.5、修改TC的事务信息存储方式

seata 的 TC 端的事务信息存储模式(store.mode)现有file、db、redis三种,file模式无需改动,直接启动即可,下面专门讲下db和redis启动步骤。

注: file模式为单机模式,全局事务会话信息内存中读写并持久化本地文件root.data,性能较高;

(1)以DB模式存储:

db模式为高可用模式,全局事务会话信息通过db共享,相应性能差些;上一节的内容已经将所有的配置信息都推送到了Nacos中,TC启动时会从Nacos中读取,因此我们修改也需要在Nacos中修改。需要修改的配置如下:

## 采用db的存储形式
store.mode=db
## druid数据源
store.db.datasource=druid
## mysql数据库
store.db.dbType=mysql
## mysql驱动
store.db.driverClassName=com.mysql.jdbc.Driver
## TC的数据库url
store.db.url=jdbc:mysql://127.0.0.1:3306/seata_server?useUnicode=true
## 用户名
store.db.user=root
## 密码
store.db.password=Nov2014

在nacos中搜索上述的配置,直接修改其中的值,比如修改 store.mode,如下图:

在这里插入图片描述

(2)以Redis模式存储:

redis模式 Seata-Server 1.3 及以上版本支持,性能较高,但存在事务信息丢失风险,所以需要提前配置合适当前场景的redis持久化配置,该模式需改动以下配置:

store.mode=redis
store.redis.host=127.0.0.1
store.redis.port=6379
store.redis.password=123456

4.1.6、启动TC

按照上述步骤全部配置成功后,则可以启动TC,在 seata-server-1.4.2\bin 目录下直接点击 seata-server.bat(windows)运行,启动成功后,启动成功后,在Nacos的服务列表中则可以看到TC已经注册进入,如下图:
在这里插入图片描述

至此,Seata 的 TC 就启动完成了…

4.2、搭建Seata 客户端(RM)

4.2.1、maven 添加 seata 依赖

<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
   <!-- 排除依赖,指定版本和服务端一致 -->
    <exclusions>
       <exclusion>
           <groupId>io.seata</groupId>
           <artifactId>seata-spring-boot-starter</artifactId>
       </exclusion>
       <exclusion>
           <groupId>io.seata</groupId>
           <artifactId>seata-all</artifactId>
       </exclusion>
   </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.4.2</version>
</dependency>
<dependency>
   <groupId>io.seata</groupId>
   <artifactId>seata-all</artifactId>
   <version>1.4.2</version>
</dependency>

注意:seata客户端的依赖版本必须要和服务端一致。

4.2.2、application.yml 添加 seate 配置

seata:
  # 这里要特别注意和nacos中配置的要保持一致,建议配置成 ${spring.application.name}-tx-group
  tx-service-group: my_test_tx_group
  registry:
    type: nacos
    nacos:
      # 配置所在命名空间ID,如未配置默认public空间
      server-addr: 127.0.0.1:8848
      namespace: XXXXXXXXXX
      group: SEATA_GROUP
      application: seata-server
      userName: nacos
      password: nacos
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: XXXXXXXXXX
      group: SEATA_GROUP
      userName: nacos
      password: nacos

tx-service-group 配置的值可以自定义,但是定义后需要在 nacos 配置中心新增 service.vgroupMapping.xxx=default 的配置,该属性一定一定要和 seata 服务端的配置一致,否则不生效;比如上述配置中的,就需要在 nacos 配置中心新增一个配置项 service.vgroupMapping.my_test-tx-group=default,并且设置分组为SEATA_GROUP,如下图:

在这里插入图片描述

注意:my_test-tx-group 仅仅是后缀,在nacos中添加配置时记得要加上前缀 service.vgroupMapping.

4.2.3、数据库中添加回滚日志表

https://github.com/seata/seata/tree/1.4.2/script/client/at/db

回滚日志表:undo_log,这是Seata要求必须有的,每个业务库都应该创建一个,SQL如下:

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 = utf8 COMMENT ='AT transaction mode undo table';

4.2.4、使用 seata 作为全局事务控制

在分布式业务入口增加全局事务注解 @GlobalTransactional,其他 service 接口无需配置;假设A服务调用B服务,那么就在A服务的方法上面加入,B服务上面不用加

/**
 * seata 的 GlobalTransactional 注解只需要加载分布式业务入口处,其他service接口无需配置,从而实现分布式事务
 */
@GlobalTransactional
@PostMapping (value = "addOrder",produces = {"application/json;charset=utf-8"})
public String addOrder(@RequestParam String title, @RequestParam int price, @RequestParam int shopId, @RequestParam int userId)
{
    shopOrderService.save(ShopOrderPojo.builder().price(price).title(title).shopId(shopId).userId(userId).build());
    storageFeignService.reduceStorage(shopId, 1);
    return "success";
}

备注:如果你进行异常捕捉,seata 将认为你已进行异常处理,就不会回滚数据了

(1)比如如果你配置了@ControllerAdvice将可能导致数据不回滚
(2)如果使用 Feign 调用分布式服务并配置了fallback,后面服务抛出异常会直接执行fallback导致无法回滚(rollbackFor = Exception.class);这时可以在fallback的实现方法内手动调用seata全局回滚,如下所示:

  @Override
    public BizResponse insertAge(Integer age) {
        //feign调用接口fallback后需要手动调用全局事务回滚
        try {
            String xid = RootContext.getXID();
            GlobalTransactionContext.reload(xid).rollback();
        } catch (TransactionException e) {
            e.printStackTrace();
        }
        return BizResponse.fail("客户端降级处理insertAge," + Thread.currentThread().getName());
    }

4.2.5、undo log 表介绍

上面介绍过 Seata 是根据 undo_log 中的记录来回滚的,但是异常回滚后 undo_log 表却为空?怎么回事,这是因为 undo_log 日志被删除了,想要看到undo_log 表中记录,我们需要打断点来看,在异常还没抛出时打断点,然后看下数据库 undo_log 表中数据情况。

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

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

相关文章

独家揭秘:Kotlin K2编译器的前世今生

独家揭秘&#xff1a;Kotlin K2编译器的前世今生 也许您已经观看了最近的 KotlinConf 2023 主题演讲&#xff0c;关于 K2 编译器的更新。什么是 K2 编译器&#xff1f; 在搞清楚这个问题之前&#xff0c;我们需要了解Kotlin 使用的不同种类的编译器及其差异&#xff0c;以及编…

Python--数据类型

Python--数据类型 <font colorblue >一、数据的分类<font colorblue >二、数值类型<font colorblue >1、整型&#xff1a;int<font colorblue >2、浮点型&#xff1a;float<font colorblue >3、复数类型&#xff1a;complex <font colorblue …

加速应用迭代与更新:Weex与小程序容器的快速开发之道

Weex是一个跨平台的移动应用开发框架&#xff0c;由阿里巴巴旗下的阿里巴巴前端团队开发。它允许开发者使用单一的代码库来构建同时适用于iOS和Android平台的移动应用。Weex使用基于Vue.js的声明式语法来描述应用程序的界面&#xff0c;并通过JavaScript运行时引擎在移动设备上…

中国人民大学与加拿大女王大学金融硕士——人到中年还有必要在职读研吗?

人到中年&#xff0c;深刻的感受到自己能够掌控的事情越来越少&#xff0c;而焦虑越来越多。事业进入瓶颈期&#xff0c;如何开拓进阶呢&#xff0c;如何做更好的自己呢&#xff1f;看到周围有人再提升学历&#xff0c;想想自己的年龄&#xff0c;不禁感叹&#xff0c;到了中年…

牛客网最热门的1000 多Java面试题,20+ 大厂必考点及Java面试框架知识点

Java 面试 “金三银四&#xff0c;金九银十”这个字眼对于程序员应该是再熟悉不过的了&#xff0c;每年的金三银四&#xff0c;金九银十都会有很多程序员找工作、跳槽等一系列的安排。说实话&#xff0c;面试中 7 分靠能力&#xff0c;3 分靠技能&#xff1b;在刚开始的时候介…

免费Midjourney来袭

发现一个镜像站&#xff0c;和之前发的镜像站不一样&#xff0c;这个集成了midjourney和chatgpt&#xff0c;且免翻&#xff0c;相信给很多很多用户都提供了便利吧&#xff01; 先把网站贴出来&#xff0c;有兴趣的伙伴可以玩一玩 关于以图生图&#xff0c;现在网站支持本地上…

好程序员:月薪2万程序员的简历,原来长这个样子!

6月份现在正是招聘季节&#xff0c;不少同学java岗位投递不少&#xff0c;但回复不多&#xff0c;根本原因可能是java面试简历不够吸引人。 你的java简历不会写&#xff1f;看看别人就知道咋写了&#xff0c;这里给大家拆解一份好程序员月薪2万的java简历。 java自我评价模块&a…

ABB CI546 3BSE012545R1 模块

ABB CI546 3BSE012545R1 模块. ABB CI546 3BSE012545R1 模块 电子电工技术的电力系统分析 1电子电工技能特色 电子电工技能是凭仗计算机技能开展起来的&#xff0c;并朝着智能化、网络化的方向开展。随着时代的开展&#xff0c;新式技能不断涌现&#xff0c;使传统电工技能运用…

2.Apollo测试部署-linux

1.创建数据库 1) 由于开发环境,测试环境, 生产环境用的一个portal&#xff0c;所以只需要创建ApolloConfigDB数据库 2) 创建后如下图: 2.部署服务apollo-adminservice,apollo-configservice 1) 分别修改两个服务下的数据库配置文件&#xff1a;/config/application-github.prop…

【Spring】Spring框架介绍,功能模块,容器知识和有关Spring的生态圈的详细讲解

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

停车场一键求助对讲系统

停车场一键求助对讲系统 适用性高&#xff0c;保障性能强 无论是商场的停车场&#xff0c;还是社区的停车场&#xff0c;我们的系统都能轻松应对。此外&#xff0c;可靠的保障性能&#xff0c;更能为车主提供便利的服务保障。 防盗警报&#xff0c;实现车位管理 在停车场内&…

【MySQL】 IS NOT NULL 和 != NULL 的区别?

背景 最近在开发小伙伴的需求&#xff0c;遇到了一个数据库统计的问题&#xff0c; is not null 结果正确 &#xff01;null 结果就不对&#xff0c;然后就激发了获取真理的想法&#xff0c;那必须的查查 咋回事嘞&#xff1f; 开整 在用MySQL的过程中&#xff0c;你是否存…

PMP考试 I 我该如何高效准备?

一&#xff1a;PMP考试的项目生命周期治理 可把PMP考试当成一个项目&#xff0c;先规划出此项目的生命周期&#xff0c;进行严格的生命周期管理和阶段治理工作&#xff0c;可简单分成3个阶段&#xff08;1个月每阶段&#xff09;&#xff1a; 阶段一&#xff1a;找到感觉 第…

Nginx源码部署1.18.0版本

文章目录 一、Nginx源码部署1.18.0版本二、Nginx服务相关参数三、Nginx相关命令四、Nginx启动进程介绍 一、Nginx源码部署1.18.0版本 依赖安装&#xff1a; yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel# gcc: C语言编辑器 nginx是C语言编写的 所以…

Servlet 数据库访问

目录 前言 测试数据 访问数据库 前言 Servlet 数据库访问之前&#xff0c;Java MySQL 连接设置相关驱动及配置。 测试数据 -- 创建表 CREATE TABLE websites ( id INT(11) NOT NULL AUTO_INCREMENT, name CHAR(20) NOT NULL DEFAULT COMMENT 站点名称, url VARCHAR…

松下伺服 报警代码40

伺服型号&#xff1a;MADLN1BE (MINAS A6B系列) 现象&#xff1a;将将编码器线电机之间拔后&#xff0c;报40号故障&#xff0c;断电重启后故障仍然存在。 1.查询松下官网提示&#xff1a; 2.下载PANATERM软件&#xff0c;连USB线&#xff0c;按如下图点警报 出现下图&#x…

mybatis 简单明了

首先定义MapperScan MapperScan会导入MapperScanRegistrar。这个类很重要。这个类注意是把path下的bean扫描的定义definition扫描进来。 这个register方法是什么时候执行的&#xff1f; 由于它是imports进来的&#xff0c;项目启动后configurationclass parse的时候会把import…

Springboot 集成Druid

Springboot 集成Druid Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。本篇主要讲解一下 Springboot中如何集成 Druid &#xff01; ​ 1.添加Druid依赖 <dependency><groupId>com.alibaba</groupId><artifactId>druid-s…

【小白向】树莓派连接手机热点后 设置静态IP

树莓派连接手机热点后 设置静态IP 1.连接至手机热点2.查看当前 IP 地址3.修改 dhcpcd.conf 文件4.重启网络服务5.检查网络设置 1.连接至手机热点 在树莓派上打开 Wi-Fi 设置&#xff0c;并选择你要连接的手机热点&#xff0c;输入密码连接热点&#xff0c;确保你已经成功连接至…

十年磨一剑,超级人工智能如果出现,人类将如何应对挑战?

一、前言 创造出ChatGPT的OpenAI公司 CEO&#xff08;Sam&#xff09;称“十年内将出现超级人工智能”&#xff0c;你别不信&#xff0c;这极有可能。 具体来说&#xff0c;我们在人工智能能力方面看到了增长速度。我们现在需要做什么&#xff0c;好为将它们引入世界做好负责任…