SpringCloudAlibaba分布式事务——Seata

news2024/11/22 17:22:42

Seata

本专栏学习内容来自尚硅谷周阳老师的视频

有兴趣的小伙伴可以点击视频地址观看

分布式事务问题

在使用分布式之前,一般都是单机单库或者是单机多库的情况,一个服务对应一个数据库或者多个数据库,这样事务的问题可以通过@Transaction解决。而在微服务应用中,原来的一个服务被拆分成了三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证,但是全局的数据一致性问题没法保证。

一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题

Seata简介

Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。官网地址

分布式事务过程

一ID

  • Transaction ID XID:全局唯一的事务ID

三组件

  • Transaction Coordinator (TC) - 事务协调者

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

  • TM (Transaction Manager) - 事务管理器

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

  • RM (Resource Manager) - 资源管理器

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

处理过程

  1. TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;
  2. XID在微服务调用链路的上下文中传播
  3. RM向TC注册分支事务,将其纳入XID对应全局事务的管辖
  4. TM向TC发起针对XID的全局提交或回滚决议
  5. TC调度XID下管辖的全部分支事务完成提交或回滚要求

image-20230425143111472

玩法

只需要使用一个@GlobalTransaction注解在业务方法上即可

Seata Server安装

小黄使用的是1.6.1版本 下载地址

下载完成后,解压压缩包,得到这么一个目录

image-20230426163359357

修改配置文件

修改conf/applicatoin.yml文件

不重要的就不贴出来了,之后要整合Nacos

  • seata.config:修改为nacos,并配置,后续回去nacos上读取配置文件
  • seata.registry:修改为nacos,表示将服务注册到nacos中
  • seata.store:修改为db,并配置MySQL地址
rver:
  port: 7091

spring:
  application:
    name: seata-server

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos: 
      server-addr: 127.0.0.1:8848  # nacos的ip端口
      group: DEFAULT_GROUP  # 对应的组,默认为DEFAULT_GROUP
      namespace: 4eed638d-b9c7-4b34-bead-7d376a0946a8 # 对应的命名空间,在nacos中配置
      username: nacos
      password: nacos
      data-id: seataServer.properties # nacos中存放seata的配置文件,后面会提该文件的使用方式,相当于seata服务启动的时候需要注册到nacos,并使用nacos中的配置文件
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos: 
      application: seata-server
      server-addr: 127.0.0.1:8848
      namespace: 4eed638d-b9c7-4b34-bead-7d376a0946a8
      group: DEFAULT_GROUP
      cluster: default
      username: nacos
      password: nacos
  store:
    # support: file 、 db 、 redis
    mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:13306/seata?useUnicode=true&rewriteBatchedStatements=true&serverTimezone=GMT
      user: root
      password: 123456
      min-conn: 5
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 100
      max-wait: 5000

创建数据表

首先创建一个seata数据库,需要注意的是,seata不同版本的数据库不相同,下载地址

image-20230426163943388

配置Nacos

在配置文件中,配置了data-id,seata启动时,将服务注册到nacos,并且使用读取seataServer.properties文件进行配置

image-20230426164034979

在相应的命名空间下,创建seataServer.properties

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
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
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
# 此处的yellowstargroup名字可以自定义,只修改这个值即可
service.vgroupMapping.yellowstargroup=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
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=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
# 默认为file,一定要改为db,我们自己的服务启动会连接不到seata
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
# 修改mysql的配置
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
# 指定seata的数据库,下面会提
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
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.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#Transaction rule configuration, only for the server
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.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

启动

双击运行/bin/seata-server.bat,seata可视化界面

并且可以看到服务也注册到了Nacos中

image-20230426164627606

Seata实战

业务说明

创建三个服务:订单、库存、账户

当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品库存,再通过远程调用账户服务来扣减用户账户里面的余额,最后在订单服务中修改订单状态为已完成。

该操作跨越三个数据库,有两次远程调用,很明显会有分布式事务问题

创建数据库

存储订单的数据库

CREATE DATABASE seata_order;

CREATE TABLE t_order (
  `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
  `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
  `count` INT(11) DEFAULT NULL COMMENT '数量',
  `money` DECIMAL(11,0) DEFAULT NULL COMMENT '金额',
  `status` INT(1) DEFAULT NULL COMMENT '订单状态:0:创建中;1:已完结' 
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


SELECT * FROM t_order;

存储库存的数据库

CREATE DATABASE seata_storage;

CREATE TABLE t_storage (
 `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
 `product_id` BIGINT(11) DEFAULT NULL COMMENT '产品id',
 `total` INT(11) DEFAULT NULL COMMENT '总库存',
 `used` INT(11) DEFAULT NULL COMMENT '已用库存',
 `residue` INT(11) DEFAULT NULL COMMENT '剩余库存'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO seata_storage.t_storage(`id`, `product_id`, `total`, `used`, `residue`)
VALUES ('1', '1', '100', '0', '100');
SELECT * FROM t_storage;

存储账户的数据库

CREATE DATABASE seata_account;

CREATE TABLE t_account (
  `id` BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
  `user_id` BIGINT(11) DEFAULT NULL COMMENT '用户id',
  `total` DECIMAL(10,0) DEFAULT NULL COMMENT '总额度',
  `used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余额',
  `residue` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用额度'
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO seata_account.t_account(`id`, `user_id`, `total`, `used`, `residue`) VALUES ('1', '1', '1000', '0', '1000');
SELECT * FROM t_account;

回滚日志表

订单-库存-账户三个库下都需要创建各自的回滚日志表

DROP TABLE IF EXISTS `undo_log`;
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';

创建模块

业务代码

这里咱们主要关心的就不是业务代码了,而是SpringCloud与Seata的整合,业务代码大家可以去小黄的gitee上自行下载,下载链接

image-20230426165011756

我们通过OpenFeign实现远程调用,具体业务代码如下

  1. 调用2001本服务orderMapper.insert(order)新建一个订单
  2. 远程调用2002库存服务storageService.decrease减少库存
  3. 远程调用2003账户服务accountService.decrease减少账户余额
  4. 调用2001本服务orderMapper.updateById修改订单状态
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Autowired
    OrderMapper orderMapper;

    @Autowired
    AccountService accountService;

    @Autowired
    StorageService storageService;

    @Override
    //@GlobalTransactional(rollbackFor = Exception.class) //全局事务注解,目前还没用
    public void create(Order order) {
        log.info("-----> 创建新订单");
        order.setStatus(0);
        orderMapper.insert(order);

        log.info("-----> 开始减库存");
        storageService.decrease(order.getProductId(),order.getCount());
        log.info("-----> 结束减库存");

        log.info("-----> 开始减余额");
        accountService.decrease(order.getUserId(),order.getMoney());
        log.info("-----> 结束减余额");

        log.info("-----> 开始更新订单状态");
        order.setStatus(1);
        orderMapper.updateById(order);
        log.info("-----> 结束更新订单状态");
    }
}

Seata整合代码

Nacos配置

需要在nacos中创建一个配置文件

image-20230426170216894

名称对应着三个地方,是有所关联的

image-20230426170521254

对于Seata来说,三个服务的配置都是一样的

相关依赖

首先是依赖,本地安装的哪个版本的Seata,就要引入哪个版本的jar包

<!--nacos依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--seata依赖需要排除掉,用了什么版本的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.6.1</version>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>1.6.1</version>
</dependency>

配置文件

只显示Seata相关配置文件

spring:
  application:
    name: seata-order-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: 4eed638d-b9c7-4b34-bead-7d376a0946a8
    alibaba:
      seata:
        tx-service-group: yellowstargroup

seata:
  service:
    vgroup-mapping:
      yellowstargroup: default # key是事务分组名称 value要和服务端的机房名称保持一致
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      namespace: 4eed638d-b9c7-4b34-bead-7d376a0946a8
      group: DEFAULT_GROUP
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: 4eed638d-b9c7-4b34-bead-7d376a0946a8
      group: DEFAULT_GROUP

这里的坑非常多,启动一直找不到service.vgroupMapping.seata-order-service-fescar-service-group

image-20230426165747038

这是因为小黄一开始是使用如下配置,经过对源码的解读,才知道这个必须配在spring.cloud.alibaba.seta.tx-service-group

image-20230426165934898

组别配好之后,启动依旧是找不到service.vgroupMapping.yellowstargroup

这是因为我们创建的配置文件属于DEFAULT_GROUP分组,最坑的来了,网上很多关于Seata的配置都是默认组别的,而Seata默认组别是SEATA_GROUP!

image-20230426170701516

Seata接管数据库

Seata需要对数据库进行接管和代理,需要一个配置文件

@Configuration
public class DataSourceProxyConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Primary
    @Bean
    public DataSourceProxy dataSource(DruidDataSource druidDataSource) {
        return new DataSourceProxy(druidDataSource);
    }
}

测试

我们故意破坏远程调用服务,这时候发现订单加了,数量减少了,但是钱没扣掉,这时候只需要在业务方法上加上@GlobalTransactional(rollbackFor = Exception.class)注解即可

Seata原理

TC/TM/RM三大组件

分布式事务的执行流程

  1. TM 开启分布式事务(TM 向 TC 注册全局事务记录)
  2. 按业务场景,编排数据库、服务等事务内资源(RM 向 TC 汇报资源准备状态 )
  3. TM 结束分布式事务,事务一阶段结束(TM 通知 TC 提交/回滚分布式事务)
  4. TC 汇总事务信息,决定分布式事务是提交还是回滚
  5. TC 通知所有 RM 提交/回滚 资源,事务二阶段结束

这样说估计大家都不是很理解,小黄也看得糊里糊涂的,接下来通过上述案例更清晰的了解一下什么是TC/TM/RM

image-20230427093824806

AT模式

Seata提供了非常多的模式供我们选择,而默认是AT模式

image-20230427093910042

整体机制

AT模式分为两个阶段

一阶段:加载

在一阶段,Seata 会拦截“业务 SQL”,

  1. 解析 SQL 语义,找到“业务 SQL”要更新的业务数据,在业务数据被更新前,将其保存成“before image”,
  2. 执行“业务 SQL”更新业务数据,在业务数据更新之后,
  3. 其保存成“after image”,最后生成行锁。

以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。

image-20230427094038200

二阶段

二阶段如果是顺利提交的话,因为业务SQL在一阶段已经提交给数据库,所以Seata只需要将一阶段保存的快照数据和行锁删除即可

image-20230427094129719

二阶段如果是回滚的话,Seata就需要回滚一阶段已经执行的业务SQL,还原业务数据

回滚方式使用before image还原业务数据,但是在还原前要先校验脏写,对比数据库数据与快照数据,如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,这种情况,需要根据配置策略来做处理。

image-20230427094221024

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

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

相关文章

Python学习:Anaconda23.3.1+spyder5.4.3+Python3.10.11环境配置

问题1&#xff1a;Anaconda安装配置教程&#xff08;真的非常详细的安装过程&#xff0c;还带环境配置&#xff09; 【参考文献】本文链接&#xff1a;Windows安装Anaconda使用教程_在奋斗的大道的博客-CSDN博客 问题2&#xff1a;Anaconda半天打不开&#xff0c;就在这转啊转…

MYSQL(六)函数

函数是指一段可以直接被另一端程序调用的代码 字符串函数 update employees set workn lpad(workno,5, 0); 数值函数 根据数据库的函数&#xff0c;生成一个六位数的随机验证码 select rpad(round(rand()*1000000, 0), 6, 0); 日期函数 流程函数

尚融宝24-标的管理

目录 一、需求介绍 &#xff08;一&#xff09;借款人申请借款 &#xff08;二&#xff09;流程 二、生成新标的 三、标的列表 &#xff08;一&#xff09;后端 &#xff08;二&#xff09;前端 四、标的详情 &#xff08;一&#xff09;后端 &#xff08;二&#xf…

FPGA动态配置si5338输出差分时钟,提供工程源码和技术支持

目录 1、前言2、设计框图3、si5338原理图设计4、si5338使用流程5、vivado工程详解6、上板调试验证并演示7、福利&#xff1a;工程代码的获取 1、前言 如今的FPGA板卡随着FPGA本身性能的提高也越来越高端&#xff0c;特别是在高速接口方面表现得越发明显&#xff0c;以Xilinx的…

Redis(10)哨兵

redis哨兵 哨兵配置步骤步骤一 启动redis节点步骤二 配置哨兵节点第三步 设置主从复制第四步 查看状态第五步 验证哨兵配置是否成功第六步 测试 哨兵配置步骤 本文将介绍redis哨兵的配置步骤。Redis哨兵是一种用于监控Redis主从复制和自动故障转移的系统 Redis哨兵是Redis的核…

“探索C++非质变算法:如何更高效地处理数据“

&#x1f4d6;作者介绍&#xff1a;22级树莓人&#xff08;计算机专业&#xff09;&#xff0c;热爱编程&#xff1c;目前在c&#xff0b;&#xff0b;阶段>——目标Windows&#xff0c;MySQL&#xff0c;Qt&#xff0c;数据结构与算法&#xff0c;Linux&#xff0c;多线程&…

无线电设备发射型号核准证(SRRC)

SRRC认证简介 SRRC为国家无线电管理委员会State Radio Regulatory Commission of the People’s Republic of China SRMC认证(又称SRRC认证)自1999年6月1日起&#xff0c;中国信息产业部(Ministry of Information Industry,MII)强制规定&#xff0c;所有在中国境内销售及使用的…

【c语言】static静态变量

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

C++【二叉搜索树】

文章目录 一、二叉搜索树&#xff08;1&#xff09;概念&#xff08;2&#xff09;操作&#xff08;3&#xff09;应用 二、BST模拟实现及函数解析&#xff08;1&#xff09;构建BST结点结构体&#xff08;2&#xff09;BST默认构造及拷贝构造&#xff08;3&#xff09;BST赋值…

2023亚马逊云科技行业峰会,汇聚行业专家分享行业数字化创新之道

从实验室扩展到真实世界&#xff0c;从前沿技术探索到医疗生命科学行业的快速创新实践&#xff0c;亚马逊云科技不断地通过数字化助力医疗和生命科学的行业创新。由上海徐汇区科委指导&#xff0c;上海枫林集团作为支持单位&#xff0c;亚马逊云科技主办的2023亚马逊云科技医疗…

yum仓库及NFS共享服务

部署yum仓库及NFS共享服务 一、yum仓库服务yum概述源种类&#xff1a; 二、安装源安装ftp源安装在线源本地源和在线源同时使用将软件包变成Yum源 三、NFS共享存储服务NFS架构NFS原理 四、NFS实操 一、yum仓库服务 yum概述 基于RPM包构建的软件更新机制可以自动解决依赖关系所…

LVS负载均衡群集部署—NAT

目录 一、群集的概述1、群集的含义2、出现高并发的解决方法3、群集的三种分类3.1负载均衡群集3.2高可用群集3.3高性能运算群集 4、负载均衡的结构 三、LVS调度器用的调度方法四、LVS的工作模式及其工作过程1.NAT模式&#xff08;VS-NAT&#xff09;2.直接路由模式&#xff08;V…

冲实习 or 全力准备秋招?

作者&#xff1a;阿秀 校招八股文学习网站&#xff1a;https://interviewguide.cn 这是阿秀的第「261」篇原创 小伙伴们大家好&#xff0c;我是阿秀。 欢迎今年参加秋招的小伙伴加入阿秀的学习圈&#xff0c;目前已经超过 2300 小伙伴加入&#xff01;去年认真准备和走下来的基…

ADKEY多按键制作阻值选择

参考链接 (10条消息) 【物尽其用】ADKEY多按键制作与经验分享_SimpleJY的博客-CSDN博客https://blog.csdn.net/qq_31247231/article/details/81013459其中的阻值选择经过仿真电路 仿真结果如下表 按键序号ad值键值差0409337113722907228151813263458742047975195028261668657…

数字硬件建模SystemVerilog-通信总线建模 --Interface方法

来到了SV最后一部分&#xff0c;预计三篇文章&#xff0c;两周更完&#xff0c;所有的思维导图如下&#xff1a; 概述 SystemVerilog Interface是modport的一种&#xff0c;但比简单的输入、输出或输入输出端口的功能更多。在其最简单的形式中&#xff0c;Interface端口将相关的…

第5章 数据结构之“链表”

链表简介 1.多个元素组成的列表。 2.元素的存储不连续&#xff0c;用next指针连在一起。 数组 vs 列表 数组&#xff1a;增删非手尾元素时往往需要移动元素。如果要在数组中增加一个元素&#xff0c;数组后面的所有元素需要往后面移动一位。如果在数组中删除一个元素&#x…

Hive ---- Hive 安装

Hive ---- Hive 安装 1. Hive安装地址2. Hive安装部署1. 安装Hive2. 启动并使用Hive 3. MySQL安装1. 安装MySQL2. 配置MySQL3. 卸载MySQL说明 4. 配置Hive元数据存储到MySQL1. 配置元数据到MySQL2. 验证元数据是否配置成功3. 查看MySQL中的元数据 5. Hive服务部署1. hiveserver…

旧版VS安装 Visual Studio 2019/2017/2015官方安装教程

安装VisualStudio找不到官方版本&#xff1f;只能找到第三方&#xff1f;害怕中毒&#xff1f; 不要急&#xff0c;本文例举了VS 2019 2017 2015的官方位置&#xff0c;不用但心装成第三方Visual Studio 百度搜索 Visual Studio 2017&#xff0c;只有第三方的包&#xff0c;而…

HBase(2):HBase数据模型

1 简介 在HBASE中&#xff0c;数据存储在具有行和列的表中。这是看起来关系数据库(RDBMS)一样&#xff0c;但将HBASE表看成是多个维度的Map结构更容易理解。 表结构如下&#xff1a; ROWKEY C1列蔟 C2列蔟 rowkey 列1 列2 列3 列4 列4 列6 列簇结构如下&#xff1a…

学系统集成项目管理工程师(中项)系列13a_人力资源管理(上)

1. 基本情况 1.1. 项目团队成员的特征 1.1.1. 高学历、高素质、流动性强、年轻、个性独立 1.2. IT行业的显著特征 1.2.1. 工作强度大 1.3. 绩效评定、招聘、留用、劳工关系、健康与安全规定及其他与管理人力资源有关的技能 1.4. 项目团队成员是项目的人力资源 1.5. 项目…