【SpirngCloud】分布式事务解决方案

news2024/12/23 6:59:07

【SpirngCloud】分布式事务解决方案

文章目录

  • 【SpirngCloud】分布式事务解决方案
    • 1. 理论基础
      • 1.1 CAP 理论
      • 1.2 BASE 理论
      • 1.3 分布式事务模型
    • 2. Seata 架构
      • 2.1 项目引入 Seata
    • 3. 强一致性分布式事务解决方案
      • 3.1 XA 模式
        • 3.1.1 seata的XA模式
        • 3.1.2 XA 模式实践
        • 3.1.3 总结
    • 4. 最终一致性分布式事务解决方案
      • 4.1 AT 模式
        • 4.1.1 AT 模式实践
        • 4.1.2 总结
      • 4.2 TCC 模式
        • 4.2.1 TCC 模式实践
        • 4.2.2 总结
      • 4.3 Saga 模式
      • 5. 四种模式总结

1. 理论基础

1.1 CAP 理论

1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标:

  1. Consistency(一致性):用户访问分布式系统中的任意节点,得到的数据必须一致
  2. Availability(可用性):用户访问集群中的任意健康节点,必须能得到响应,而不是超时或拒绝
  3. Partition tolerance(分区容错性)
    • Partition(分区):因为网络故障或其它原因导致分布式系统中的部分节点与其它节点失去连接,形成独立分区。
    • Tolerance(容错):在集群出现分区时,整个系统也要持续对外提供服务

分布式无法同时满足这三个指标,这个结论就叫做 CAP理论 。凡是分布式系统就一定会出现分区,集群又必须对外提供服务,那么就认为 P 一定要实现,那么就 CA 之间就要做出取舍,要嘛 CP 要嘛 AP

image-20230722225854329


1.2 BASE 理论

BASE 理论是对 CAP 的一种解决思路,包含三个思想:

  • Basically Available(基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
  • Soft State(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态。
  • Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。

而分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴 CAP定理BASE理论

  • AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。
  • CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。

1.3 分布式事务模型

解决分布式事务,各个子系统之间必须能感知到彼此的事务状态,才能保证状态一致,因此需要一个事务协调者来协调每一个事务的参与者(子系统事务)。

这里的子系统事务,称为分支事务;有关联的各个分支事务在一起称为全局事务

image-20230722231641345


2. Seata 架构

Seata事务中有三个重要的角色:

  • TC (Transaction Coordinator) - **事务协调者:**维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) - **事务管理器:**定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - **资源管理器:**管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

image-20230723171119245

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

  1. XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
  2. TCC模式:最终一致的分阶段事务模式,有业务侵入
  3. AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
  4. SAGA模式:长事务模式,有业务侵入

2.1 项目引入 Seata

首先在项目中引入依赖:

<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <!--版本较低,1.3.0,因此排除--> 
        <exclusion>
            <artifactId>seata-spring-boot-starter</artifactId>
            <groupId>io.seata</groupId>
        </exclusion>
    </exclusions>
</dependency>
<!--seata starter 采用1.4.2版本-->
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>${seata.version}</version>
</dependency>

项目配置:

seata:
  registry:
    type: nacos # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址
    # 参考tc服务自己的registry.conf中的配置,
    # 包括:地址、namespace、group、application-name 、cluster
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: "" #空就是public
      group: DEFAULT_GROUP
      application: seata-tc-server
      username: nacos
      password: nacos
  tx-service-group: seata-demo # 事务组,根据这个获取tc服务的cluster名称
  service:
    vgroup-mapping: # 事务组与TC服务cluster的映射关系
      seata-demo: SH

3. 强一致性分布式事务解决方案

3.1 XA 模式

XA模式原理:XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范 描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范 提供了支持。

如果事务都成功执行,那么如下图所示:

image-20230723175124370

如果任意一个事务执行失败,那么如下图所示:

image-20230723175212596


3.1.1 seata的XA模式

seata的XA模式做了一些调整,但大体上相似:

RM一阶段的工作

  1. 注册分支事务到TC
  2. 执行分支业务sql但不提交
  3. 报告执行状态到TC

TC二阶段的工作

  1. TC检测各分支事务执行状态
    • 如果都成功,通知所有 RM 提交事务
    • 如果有失败,通知所有 RM 回滚事务

RM二阶段的工作

  1. 接收TC指令,提交或回滚事务

image-20230723180153268


3.1.2 XA 模式实践

Seata的starter已经完成了XA模式的自动装配,实现非常简单,步骤如下:

  1. 修改每个微服务中的 application.yml 配置文件,开启XA模式:
seata:
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: "" #空就是public
      group: DEFAULT_GROUP
      application: seata-tc-server
      username: nacos
      password: nacos
  tx-service-group: seata-demo #事务组名称
  service:
    vgroup-mapping: #事务组与cluster的映射关系
      seata-demo: SH
  data-source-proxy-mode: XA #开启数据源代理的XA模式
  1. 给发起全局事务的入口方法添加 @GlobalTransactional 注解,本例中是OrderServiceImpl中的create方法:
@Override
@GlobalTransactional
public Long create(Order order) {
    // 创建订单
    orderMapper.insert(order);
    try {
        // 扣用户余额
        accountClient.deduct(order.getUserId(), order.getMoney());
        // 扣库存
        storageClient.deduct(order.getCommodityCode(), order.getCount());

    } catch (FeignException e) {
        log.error("下单失败,原因:{}", e.contentUTF8(), e);
        throw new RuntimeException(e.contentUTF8(), e);
    }
    return order.getId();
}

3.1.3 总结

XA 模式的优点是什么?

  • 事务的强一致性,满足 ACID 原则。
  • 常用数据库都支持,实现简单,并且没有代码侵入。

XA 模式的缺点是什么?

  • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差。
  • 依赖关系型数据库实现事务

4. 最终一致性分布式事务解决方案

4.1 AT 模式

AT模式同样是分阶段提交的事务模型,不过却弥补了 XA 模型中资源锁定周期过长的缺陷。

阶段一 RM 的工作:

  1. 注册分支事务
  2. 记录 undo-log(数据快照)
  3. 执行业务sql并提交
  4. 报告事务状态

阶段二提交时 RM 的工作:

  1. 删除 undo-log 即可

阶段二回滚时 RM 的工作:

  1. 根据 undo-log 恢复数据到更新之前

image-20230723221703552

AT模式有一个缺陷就是“写丢失”,如下图所示:

image-20230723222230184

为了解决“写丢失”问题,AT模式引入了“全局锁”概念,由TC记录当前正在操作某行数据的事务,该事务持有全局锁,具备执行权。

image-20230723223959913

但是这种方法还是有一种问题,如果一个不是由seata管理的事务去修改money值,那么还是会导致“写丢失”,如下图所示:

image-20230723224352817

那么我们最好杜绝这种情况的发生,让包含修改money值的事务都受到seata的管理;或是像上图一样利用乐观锁的思想。


4.1.1 AT 模式实践

AT模式中的快照生成、回滚等动作都是由框架自动完成,没有任何代码侵入,因此实现非常简单。

  1. 在TC服务关联的数据库中导入lock_table,在微服务相关的数据库中导入 undo_log
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log`  (
  `branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id',
  `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'global transaction id',
  `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci 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 INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact;

-- ----------------------------
-- Records of undo_log
-- ----------------------------



-- ----------------------------
-- Table structure for lock_table
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table`  (
  `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_id` bigint(20) NULL DEFAULT NULL,
  `branch_id` bigint(20) NOT NULL,
  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gmt_create` datetime NULL DEFAULT NULL,
  `gmt_modified` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`row_key`) USING BTREE,
  INDEX `idx_branch_id`(`branch_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;


SET FOREIGN_KEY_CHECKS = 1;
  1. 修改配置文件,将事务模式修改为AT模式:
seata:
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: "" #空就是public
      group: DEFAULT_GROUP
      application: seata-tc-server
      username: nacos
      password: nacos
  tx-service-group: seata-demo #事务组名称
  service:
    vgroup-mapping: #事务组与cluster的映射关系
      seata-demo: SH
  data-source-proxy-mode: AT #开启数据源代理的AT模式
  1. 给发起全局事务的入口方法添加 @GlobalTransactional 注解。

4.1.2 总结

简述AT模式和XA模式的最大区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
  • XA模式依赖数据库机制实现回滚,AT模式利用数据快照实现数据回滚。
  • XA模式强一致,AT模式最终一致

AT模式的优点

  • 一阶段完成直接提交事务,释放数据库资源,性能比较好
  • 利用全局锁实现读写隔离(XA模式锁定数据库资源的情况下读写都被阻塞)
  • 没有代码侵入,框架自动完成回滚和提交

AT模式的缺点:

  • 两阶段之间属于软状态,属于最终一致
  • 框架的快照功能会影响性能,但是比XA模式要好很多

4.2 TCC 模式

TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复。需要实现三个方法:

  • Try:资源的检测和预留。
  • Confirm:完成资源操作业务,要求 Try 成功 Confirm 一定要能成功。
  • Cancel:预留资源释放,可以理解为try的反向操作。

举例,一个扣减用户余额的业务。假设账户A原来余额是100,需要余额扣减30元。

  1. 阶段一(Try):检查余额是否充足,如果充足则冻结金额增加30元,可用余额扣除30

image-20230724141241798

  1. 阶段二:假如要提交(Confirm),则冻结金额扣减30

image-20230724141258946

  1. 阶段二:如果要回滚(Cancel),则冻结金额30,可用余额增加30

image-20230724141323763


TCC的工作模型图如下所示:

image-20230724141348547


4.2.1 TCC 模式实践

需求如下:

  • 修改account-service,编写try、confirm、cancel逻辑
  • try业务:添加冻结金额,扣减可用金额
  • confirm业务:删除冻结金额
  • cancel业务:删除冻结金额,恢复可用金额
  • 保证confirm、cancel接口的幂等性
  • 允许空回滚
  • 拒绝业务悬挂

当某分支事务的try阶段阻塞时,可能导致全局事务超时而触发二阶段的cancel操作。在未执行try操作时先执行了cancel操作,这时cancel不能做回滚,就是空回滚。对于已经空回滚的业务,如果以后继续执行try,就永远不可能confirm或cancel,这就是业务悬挂。应当阻止执行空回滚后的try操作,避免悬挂。

image-20230724145837218

为了实现空回滚、防止业务悬挂,以及幂等性要求。我们必须在数据库记录冻结金额的同时,记录当前事务id和执行状态,为此我们设计了一张表:

CREATE TABLE `account_freeze_tbl` (
  `xid` varchar(128) NOT NULL,
  `user_id` varchar(255) DEFAULT NULL COMMENT '用户id',
  `freeze_money` int(11) unsigned DEFAULT '0' COMMENT '冻结金额',
  `state` int(1) DEFAULT NULL COMMENT '事务状态,0:try,1:confirm,2:cancel',
  PRIMARY KEY (`xid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

业务分析

image-20230724150009665

声明TCC接口

TCC的Try、Confirm、Cancel方法都需要在接口中基于注解来声明,语法如下:

@LocalTCC
public interface AccountTCCService {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                @BusinessActionContextParameter(paramName = "money") int money);

    boolean confirm(BusinessActionContext ctx);

    boolean cancel(BusinessActionContext ctx);
}

原业务方法如下所示:

@Slf4j
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        log.info("开始扣款");
        try {
            accountMapper.deduct(userId, money);
        } catch (Exception e) {
            throw new RuntimeException("扣款失败,可能是余额不足!", e);
        }
        log.info("扣款成功");
    }
}

使用 TCC 模式后业务方法如下所示:

@Slf4j
@Service
public class AccountTccServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountFreezeMapper accountFreezeMapper;

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        //1.获取事务id
        String xid = RootContext.getXID();
        //业务悬挂
        //判断 accountFreeze 中是否有冻结记录,如果有,一定是 CANCEL 执行过,我要拒绝业务
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        if (accountFreeze != null) {
            //CANCEL 执行过,拒绝业务
            return;
        }
        //2.扣减可用余额
        accountMapper.deduct(userId, money);
        //3.记录冻结金额,事务状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);
        accountFreezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        //1.获取事务id
        String xid = ctx.getXid();
        //2.根据id删除冻结记录
        int count = accountFreezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        //0.查询冻结记录
        String xid = ctx.getXid();
        String userId = ctx.getActionContext("userId").toString();
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        //1.空回滚的判断,判断 accountFreeze 是否为null,为null证明try没执行,需要空回滚
        if (accountFreeze == null) {
            //为null证明try没执行,需要空回滚
            AccountFreeze freeze = new AccountFreeze();
            freeze.setUserId(userId);
            freeze.setFreezeMoney(0);
            freeze.setState(AccountFreeze.State.CANCEL);
            freeze.setXid(xid);
            accountFreezeMapper.insert(freeze);
            return true;
        }
        //2.幂等判断,cancel方法超时会重试
        if (accountFreeze.getState() == AccountFreeze.State.CANCEL) {
            //已经处理过一次 CANCEL 了,无需重复处理
            return true;
        }
        //3.恢复可用余额
        accountMapper.refund(accountFreeze.getUserId(), accountFreeze.getFreezeMoney());
        //4.将冻结金额清零,状态改为 CANCEL
        accountFreeze.setFreezeMoney(0);
        accountFreeze.setState(AccountFreeze.State.CANCEL);
        int count = accountFreezeMapper.updateById(accountFreeze);
        return count == 1;
    }
}

AT模式 和 TCC模式可以混用。


4.2.2 总结

TCC模式的每个阶段是做什么的?

  • Try:资源检查和预留
  • Confirm:业务执行和提交
  • Cancel:预留资源的释放

TCC的优点是什么?

  • 一阶段完成直接提交事务,释放数据库资源,性能好
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库

TCC的缺点是什么?

  • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
  • 软状态,事务是最终一致
  • 需要考虑Confirm和Cancel的失败情况,做好幂等处理

4.3 Saga 模式

Saga模式是SEATA提供的长事务解决方案。也分为两个阶段:

  • 一阶段:直接提交本地事务
  • 二阶段:成功则什么都不做;失败则通过编写补偿业务来回滚

Saga模式的优点:

  • 事务参与者可以基于事件驱动实现异步调用,吞吐高
  • 一阶段直接提交事务,无锁,性能好
  • 不用编写TCC中的三个阶段,实现简单

Saga模式的缺点:

  • 软状态持续时间不确定,时效性差
  • 没有锁,没有事务隔离,会有脏写

image-20230724190142594


5. 四种模式总结

image-20230724190234800

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

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

相关文章

ARP协议(地址解析协议)

文章目录 ARP协议&#xff08;地址解析协议&#xff09;MAC地址ARP协议ARP具体实现同一链路不同链路 ARP 缓存缓存查询 APR请求/响应报文 ARP协议&#xff08;地址解析协议&#xff09; MAC地址 MAC 地址的全称是 Media Access Control Address&#xff0c;即媒体访问控制地址…

全网最细,时序数据库InfluxDB详解,你不知道的都在这...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 直接上图片&#…

新一代信息技术浪潮下的DPU力量 中科驭数亮相2023中国互联网大会

7月18日&#xff0c;由中国互联网协会主办&#xff0c;北京经济技术开发区管委会、北京市通信管理局、工业和信息化部新闻宣传中心联合主办的2023&#xff08;第二十二届&#xff09;中国互联网大会如约而至&#xff01;中科驭数出席本次大会&#xff0c;高级副总裁张宇应邀在新…

Python内置函数系统学习(3)——数据转换与计算(详细语法参考 + 参数说明 + 具体示例)详解 min()函数 | lambda 真的牛啊

两岸猿声啼不住&#xff0c;轻舟已过万重山&#xff01; &#x1f3af;作者主页&#xff1a; 追光者♂&#x1f525; &#x1f338;个人简介&#xff1a; &#x1f496;[1] 计算机专业硕士研究生&#x1f496; &#x1f31f;[2] 2022年度博客之星人工智能领域TOP4&#x1f…

java项目之社区生活超市管理系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的社区生活超市管理系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框…

【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(7 月 25 日论文合集)

文章目录 一、Automotive Object Detection via Learning Sparse Events by Temporal Dynamics of Spiking Neurons1.2 Exposing the Troublemakers in Described Object Detection1.3 AMAE: Adaptation of Pre-Trained Masked Autoencoder for Dual-Distribution Anomaly Dete…

【档案专题】四、电子档案形成与收集

导读&#xff1a;主要针对电子档案形成与收集相关内容介绍。对从事电子档案管理信息化的职业而言&#xff0c;不断夯实电子档案管理相关理论基础是十分重要。只有通过不断梳理相关知识体系和在实际工作当中应用实践&#xff0c;才能走出一条专业化加职业化的道路&#xff0c;从…

25.4 matlab里面的10中优化方法介绍——最速下降法(matlab程序)

1.简述 matlab实现最速下降法 定义&#xff1a;沿负梯度方向进行搜索的算法&#xff08;负梯度方向为最速下降方向&#xff09; 算法步骤&#xff1a; 步0&#xff1a;选取初始点x0&#xff0c;容许误差是e[0~1],令k1 步1&#xff1a;计算目标函数的梯度gk▽f(xk)) 若 ||g…

网工内推 | 初级网工、Linux运维,IP证书优先

01 光联世纪 招聘岗位&#xff1a;初级网络工程师 职责描述&#xff1a; 1.负责日常基础网络运维工作&#xff1b; 2.负责日常网络监控工作&#xff1b; 3.负责现场基础技术支持工作&#xff1b; 4.主动进行自我迭代&#xff0c;不断提升技术能力和个人素质。 任职要求&#x…

行为型模式 - 观察者模式

概述 定义&#xff1a; 又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时&#xff0c;会通知所有的观察者对象&#xff0c;使他们能够…

jQuery的DOM操作之笔记总结

jQuery的DOM操作之笔记总结 首先我们来介绍一下什么是DOM 简述&#xff1a; 1.DOM全称Document Object Model&#xff08;文档对象模型&#xff09;。 2.每个文档都是一棵DOM结构的树&#xff0c;文档里的很多元素&#xff0c;就像树上的很多节点&#xff0c;或是分叉的树枝…

【Git】git仓库完整迁移

代码仓库&#xff0c;在公司有两个团队在做&#xff0c;并且gitlab所在环境不互通。有一个团队做的时间久一点&#xff0c;另一个团队想要用并做一些定制。就需要将代码转移到另一个gitlab管理。 参考&#xff1a;【Git】git仓库完整迁移&#xff08;代码&#xff0c;分支&…

ubuntu挂载ext4文件系统

文章目录 1.虚拟机分配10G磁盘用来挂载ext4文件系统2.磁盘分区3.创建文件系统4.挂载文件系统5.卸载文件系统6.使用ior测试ext4三种日志模式&#xff08;1&#xff09;ordered&#xff08;2&#xff09;journal&#xff08;3&#xff09;writeback 1.虚拟机分配10G磁盘用来挂载e…

编码类型 ASCII URLcode编码 Unicode编码 utf编码理解

编码类型 ASCII URLcode编码 Unicode编码 utf编码理解 bin是二进制 oct是八进制 hex是16进制 Ord()检测ASCII码&#xff0c;python3也可查中文 HTML实体编码能被html页面解析&#xff0c;使用ord&#xff08;&#xff09;对单个字符查看转换后结果&#xff0c;字母就是ASCII…

B2B2C开源多语言多商户跨境外贸网站部署开发

随着全球化的发展&#xff0c;跨境外贸成为了许多企业拓展业务的重要方向。搭建一个B2B2C开源多语言多商户跨境外贸网站&#xff0c;将有助于实现企业的全球化经营。那么&#xff0c;如何搭建一个B2B2C跨境外贸网站呢&#xff1f; 一、选择合适的开源平台 在搭建一个B2B2C跨境…

【设计模式】单例设计模式详解(包含并发、JVM)

文章目录 1、背景2、单例模式3、代码实现1、第一种实现&#xff08;饿汉式&#xff09;为什么属性都是static的&#xff1f;2、第二种实现&#xff08;懒汉式&#xff0c;线程不安全&#xff09;3、第三种实现&#xff08;懒汉式&#xff0c;线程安全&#xff09;4、第四种实现…

用i18next使你的应用国际化-Vue

ref: https://www.i18next.com/ 在vue项目中安装相关依赖&#xff1a; i18nexti18next-vuei18next-browser-languagedetector&#xff0c;用于检测用户语言 npm install i18next i18next-vue i18next-browser-languagedetector创建i18n.js文件&#xff1a; import i18next f…

FUNBOX_SCRIPTKIDDIE靶机详解

FUNBOX_SCRIPTKIDDIE靶机复盘 这个靶场给了太多的干扰因素&#xff0c;当你打完后反过来再看是非常简单的一个靶场&#xff0c;但是你打的过程中却会觉得非常难&#xff0c;干扰因素实在天多了。 题目中给了说加一条hosts&#xff0c;实际没用上。 对IP进行一个单独扫描后发现…

【设计模式——学习笔记】23种设计模式——建造者模式Builder(原理讲解+应用场景介绍+案例介绍+Java代码实现)

介绍 建造者模式又叫生成器模式&#xff0c;是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别)&#xff0c;使这个抽象过程的不同实现方法可以构造出不同属性的对象建造者模式是一步一步创建一个复杂的对象&#xff0c;它允许用户只通过指定复杂对象的类型和…

【MATLAB第60期】基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型

【MATLAB第60期】源码分享 | 基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型 一、简要介绍 ARMAX模型相比ARMA考虑了影响因素 &#xff0c;即可以实现基于时间序列数据的回归预测。目前&#xff0c;ARMAX预测未来功能存在困难&#xff0c;本篇文章不予介绍。大致思路…