SpringCloud Alibaba - Seata 四种分布式事务解决方案(TCC、Saga)+ 实践部署(下)

news2024/11/20 18:32:01

目录

一、Seata 分布式解决方案

1.1、TCC 模式

1.1.1、TCC 模式理论

对比 TCC 和 AT 模式的一致性和隔离性

TC 的工作模型

1.2.2、TCC 模式优缺点

1.2.3、TCC 模式注意事项:空回滚

1.2.4、TCC 模式注意事项:业务悬挂

1.2.5、实现 TCC 模式

案例:在用户余额扣减服务中,实现 TCC 模式.

实现案例

a)TCC 的 try、confirm、cancel 方法都需要在接口中基于注解来声明

b)建表

c)对应刚刚上述所描述的实现思路,可以基本实现(未考虑空回滚 和 业务悬挂) 

d)考虑空回滚

e)幂等问题

f)业务悬挂问题

g)到此,整个业务完成.

1.2、Saga 模式

1.2.1、Saga 模式理论

1.2.2、saga 模式优缺点


一、Seata 分布式解决方案


1.1、TCC 模式

1.1.1、TCC 模式理论

TCC 模式和 AT 模式很相似,第一阶段都是独立事务,执行完了直接提交,不同的是 TCC 模式不用去加锁,也不用生成快照,因此性能上会更好.

TCC 模式的第二阶段是基于人工编码的方式来实现数据恢复的,不像 AT 是自动实现的.

人工编码的方式需要实现三个方法,分别是 try、confirm、cancel.

  • try:用来进行资源的检测和预留. 也就是说我需要修改某个资源的时候,先把这个资源预留下来,等到第二阶段的时候在对这个资源进行一个具体的操作.
  • cancel:如果第二阶段需要进行回滚,就执行 cancel. cancel 是对预留资源的一个释放(可以理解为对 try 的反向操作).
  • confirm:完成资源业务操作(这里要求 try 成功,那么 confirm 一定要成功).

例如现在我的账户余额是 100 元,现在要扣掉 30 元.  如果分成 try、cancel、confirm 这三个阶段.

  1. try 阶段:做资金的检测和预留.  检测就是判断余额够不够(当前余额为 100,要扣 30 肯定是够的).  预留就是说如果余额充足,就先把要扣的 30 元金额冻结起来,也就是说可用余额扣减 30,冻结金额增加 30,而总金额是没有变化的.
  2. confirm 阶段:如果 try 阶段执行成功了,就会执行 confirm 进行提交.  这里就提交就是直接把 try 阶段冻结的 30 元金额直接扣掉,因此总金额就变成 70 元了.
  3. cancel 阶段:如果有人在执行 try 阶段失败了,就要执行 cancel 进行回滚.  这里就是对 try 阶段的一个反向操作.  在 try 阶段冻结的30元余额解冻,可用余额也就增加了 30.   因此从 try 到 cancel 可以看到总金额是没有变化的,变化的仅仅是冻结的部分.
对比 TCC 和 AT 模式的一致性和隔离性

一致性:首先第一阶段两个模式都是各自提交各自的事务,因此两种模式都有可能出现提交成功和失败的情况,导致状态不一致,需要通过第二阶段来调整.  也就是说这两种模式都是最终一致性.

隔离性:AT 模式是需要通过加锁实现隔离(在第一、第二阶段持有全局锁),而 TCC 模式下不需要加锁隔离,因为在第一阶段是通过冻结来实现隔离(冻结了一部分金额),就算此时有另一个事务也要冻结金额,那就直接从可用余额中取一部分冻结,所以事务之间都没有任何影响,不需要加锁,那么 TCC 模式的性能就要比 AT 模式好很多了.

TC 的工作模型

第一阶段:

这里大部分都和 AT 很像,一开始都是由 TM 去开启全局事务并注册到 TC 上面,然后 TM 去通知每一个分支事务去执行,然后请求被 RM 拦截,RM 就会先去注册分之十五,然后去执行 try 预留资源,执行完后直接提交,随后向 TC 报告事务的状态(资源预留执行成功了?还是失败了).

第二阶段:

TM 通知 TC 事务结束了,那么 TC 就要对事务的状态做判断了.  如果分支预留资源成功了,就直接执行 confirm 提交即可;如果发现其中任意一个有问题,就要执行 cancel 逻辑.

1.2.2、TCC 模式优缺点

优点:

性能高:第一阶段执行完直接提交事务,并且既不用生成快照,也不用使用全局锁. 可以认为是所有分布式事务模型中性能最好的.

不依赖数据库:不需要依赖于事务性的数据库,因为是靠预留资源来做代偿的.  也就是说不仅可以使用 mysql 这种关系型数据库,也可以使用 redis 这种非关系型数据库去实现 TCC 模式.

缺点:

代码侵入高:try、confirm、cancel 这三个方法需要人工编写.

软状态,最终一致:第一阶段执行完后,直接提交事务.

考虑幂等:将来 confirm 和 cancel 可能会执行失败,Seata 看到失败了就会重试,就可能造成死循环.  因此要考虑各种健壮性.

1.2.3、TCC 模式注意事项:空回滚

问题:

在将执行某个分支事务的时候,发现执行分支事务的请求因为某种原因(网络抖动)阻塞住了,一旦阻塞的时间超过了超时时间,就会将超时的错误报告给 TC,然后 TC 就会告诉这个分支事务的 RM:“那你去回滚吧”,此时 RM 就会去执行 cancel 的业务. 

这就导致本身你没有执行 try 预留资源,现在却要执行 cancel 去释放预留资源.  比方说 try 的业务就是去冻结 30 元的余额,但是在没有进行 try 之前却要进行释放 30 元冻结余额的业务,这不就出事了吗?

解决方案:

因此这里需要做一个空回滚. 

在 try 执行请求因为某种原因阻塞时,可能会导致全局事务超时,从而先触发了 cancel 逻辑,此时根本就没有做资源预留,就不能回滚,并且也不能报错(不然 Seata 会以为 cancel 出问题了,会重试,最后导致死循环).  那么空回滚只需要我们返回一个正常结束即可.

1.2.4、TCC 模式注意事项:业务悬挂

问题:

在执行完空回滚之后,try 逻辑的请求阻塞突然通畅,就会去执行资源预留业务,但是资源预留了之后就没有后续了(已经执行过 cancel 中的空回滚了),既没有 cancel,也没有 confirm,业务只执行了一半.  这就是业务悬挂.

比如说我本来有 100 元余额,执行完空回滚后,try逻辑突然通常,冻结了我 30 元的可用余额,然后也没有后续业务了,就导致我这 30 元有是有,但是却一直用不了.

解决办法:

在执行 try 的时候,先判断一下是否回滚过,如果回滚过了 try 就不能执行了.  同样在执行 cancel 的时候,需要判断一下,try 是不是已经执行了,如果 try 没有执行,就去做一个空回滚.

怎么知道 try 到底有没有执行过呢?这就需要在数据库中在创建一个表,用来记录事务的状态(记录上一步是执行了 try 呢?还是cancel?还是confirm?).  

1.2.5、实现 TCC 模式

案例:在用户余额扣减服务中,实现 TCC 模式.

那么实现的思路如下:

  1. try:扣减可用余额,添加冻结金额.
  2. confirm:删除冻结金额.
  3. cancel:恢复可用金额,删除冻结金额.
  4. 注意事项:保证 confirm、cancel 接口的幂等性,注意 空回滚 和 业务悬挂.

实现案例
a)TCC 的 try、confirm、cancel 方法都需要在接口中基于注解来声明

语法如下:

@LocalTCC
public interface TCCService {
    /**
     * Try逻辑,@TwoPhaseBusinessAction中的name属性要与当前方法名一致,用于指定Try逻辑对应的方法
     * commitMethod 用来指定 confirm 逻辑,值必须对应自己实现的方法名. rollbackMethod 表示 cancel 逻辑,值必须对应自己实现的方法名.
     */
    @TwoPhaseBusinessAction(name = "prepare", commitMethod = "confirm", rollbackMethod = "cancel")
    void prepare(@BusinessActionContextParameter(paramName = "param") String param);
    /**
     * 二阶段confirm确认方法、可以另命名,但要保证与commitMethod一致 
     *
     * @param context 上下文,可以传递try方法的参数
     * @return boolean 执行是否成功
     */
    boolean confirm (BusinessActionContext context);
    /**
     * 二阶段回滚方法,要保证与rollbackMethod一致
     */
    boolean cancel (BusinessActionContext context);
}

根据上述语法,就可以编写用户余额冻结服务的接口 AccountTCCService ,如下

@LocalTCC
public interface AccountTCCService {

    /**
     * try:冻结指定余热
     * @param userId
     * @param money
     */
    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                @BusinessActionContextParameter(paramName = "money") int money);

    /**
     * 删除冻结余额
     * @param ctx
     * @return
     */
    boolean confirm(BusinessActionContext ctx);

    /**
     * 删除冻结余额,恢复可用余额
     * @param ctx
     * @return
     */
    boolean cancel(BusinessActionContext ctx);

}

b)建表

这里我们已经有了用户金额表,如下:

这里我们还需要创建 用户冻结金额表 ,如下:

CREATE TABLE `account_freeze_tbl`  (
  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `freeze_money` int(11) UNSIGNED NULL DEFAULT 0,
  `state` int(1) NULL DEFAULT NULL COMMENT '事务状态,0:try,1:confirm,2:cancel',
  PRIMARY KEY (`xid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

对应实体类如下:

@Data
@TableName("account_freeze_tbl")
public class AccountFreeze {
    @TableId(type = IdType.INPUT)
    private String xid;
    private String userId;
    private Integer freezeMoney;
    private Integer state;

    public static abstract class State {
        public final static int TRY = 0;
        public final static int CONFIRM = 1;
        public final static int CANCEL = 2;
    }
}

c)对应刚刚上述所描述的实现思路,可以基本实现(未考虑空回滚 和 业务悬挂) 

AccountTCCService 接口,如下:

@Slf4j
@Service
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountFreezeMapper freezeMapper;


    @Override
    @Transactional
    public void deduct(String userId, int money) {
        //1.获取事务 id
        String xid = RootContext.getXID();
        //2.扣减可用余额
        accountMapper.deduct(userId, money);
        //3.增加冻结金额,并记录当前事务的状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setXid(xid);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        //1.添加事务 id
        String xid = RootContext.getXID();
        //2.根据 id 删除冻结记录
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        //1.查询冻结记录
        String xid = RootContext.getXID();
        AccountFreeze freeze = freezeMapper.selectById(xid);
        //2.恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        //3.清理冻结余额,状态修改为 cancel
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }

}
d)考虑空回滚

考虑在执行 try 逻辑阻塞超时,执行了 cancel 逻辑,那么就需要考虑空回滚.  主要记录 cancel 状态即可.

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        //1.查询冻结记录
        String xid = RootContext.getXID();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        //a. 空回滚判断
        if (freeze == null) {
            //这里主要记录当前的 cancel 状态
            freeze = new AccountFreeze();
            //这里能拿到 userId 和 money 是因为在 AccountTCCService 接口中通过 BusinessActionContextParameter 注解注册了
            String userId = ctx.getActionContext("userId").toString();
            freeze.setUserId(userId);
            freeze.setXid(xid);
            freeze.setFreezeMoney(0);
            freeze.setState(AccountFreeze.State.TRY);
            freezeMapper.insert(freeze);
        }

        //2.恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        //3.清理冻结余额,状态修改为 cancel
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }

e)幂等问题

第一次超时了,进行空回滚(添加 freeze,设置状态为 cancel),第二次又超时了,freeze 不为空,就会进行恢复金额逻辑.  这就出问题了,不能进行恢复金额操作,因此,这里需要进行判断,如果处理过了,直接返回 true 即可.

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        //1.查询冻结记录
        String xid = RootContext.getXID();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        //a. 空回滚判断
        if (freeze == null) {
            //这里主要记录当前的 cancel 状态
            freeze = new AccountFreeze();
            //这里能拿到 userId 和 money 是因为在 AccountTCCService 接口中通过 BusinessActionContextParameter 注解注册了
            String userId = ctx.getActionContext("userId").toString();
            freeze.setUserId(userId);
            freeze.setXid(xid);
            freeze.setFreezeMoney(0);
            freeze.setState(AccountFreeze.State.TRY);
            freezeMapper.insert(freeze);
        }

        //b.幂等问题:第一次超时了,进行空回滚,第二次又超时了,freeze 不为空,就会进行恢复金额逻辑(这就出问题了).
        if(freeze.getState() == AccountFreeze.State.CANCEL) {
            //已经处理过依次 cancel 了,无需重复处理
            return true;
        }

        //2.恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        //3.清理冻结余额,状态修改为 cancel
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }

confirm 为什么不考虑幂等了?

因为 confirm 逻辑是删除冻结记录,底层就是 sql 调用 delete.  因此即使操作多次,也无妨.

f)业务悬挂问题

处理过 cancel 之后,就没必要再处理 try 了,因此这里只需要判断 freeze 是否存在冻结记录,如果有,拒绝即可.

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        //1.获取事务 id
        String xid = RootContext.getXID();

        //a. 业务悬挂问题处理:判断 freeze 中是否有冻结记录,如果有,一定是 cancel 执行过,要拒绝业务
        AccountFreeze oldFreeze = freezeMapper.selectById(xid);
        if(oldFreeze != null) {
            return;
        }

        //2.扣减可用余额
        accountMapper.deduct(userId, money);
        //3.增加冻结金额,并记录当前事务的状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setXid(xid);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freezeMapper.insert(freeze);
    }

g)到此,整个业务完成.

全代码如下:

@Slf4j
@Service
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountFreezeMapper freezeMapper;


    @Override
    @Transactional
    public void deduct(String userId, int money) {
        //1.获取事务 id
        String xid = RootContext.getXID();

        //a. 业务悬挂问题处理:判断 freeze 中是否有冻结记录,如果有,一定是 cancel 执行过,要拒绝业务
        AccountFreeze oldFreeze = freezeMapper.selectById(xid);
        if(oldFreeze != null) {
            return;
        }

        //2.扣减可用余额
        accountMapper.deduct(userId, money);
        //3.增加冻结金额,并记录当前事务的状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setXid(xid);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        //1.添加事务 id
        String xid = RootContext.getXID();
        //2.根据 id 删除冻结记录
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        //1.查询冻结记录
        String xid = RootContext.getXID();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        //a. 空回滚判断
        if (freeze == null) {
            //这里主要记录当前的 cancel 状态
            freeze = new AccountFreeze();
            //这里能拿到 userId 和 money 是因为在 AccountTCCService 接口中通过 BusinessActionContextParameter 注解注册了
            String userId = ctx.getActionContext("userId").toString();
            freeze.setUserId(userId);
            freeze.setXid(xid);
            freeze.setFreezeMoney(0);
            freeze.setState(AccountFreeze.State.TRY);
            freezeMapper.insert(freeze);
        }

        //b.幂等问题:第一次超时了,进行空回滚,第二次又超时了,freeze 不为空,就会进行恢复金额逻辑(这就出问题了).
        if(freeze.getState() == AccountFreeze.State.CANCEL) {
            //已经处理过依次 cancel 了,无需重复处理
            return true;
        }

        //2.恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        //3.清理冻结余额,状态修改为 cancel
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }

}

1.2、Saga 模式

1.2.1、Saga 模式理论

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

第一阶段:

与 AT 一样,直接提交本地事务.

第二阶段:

如果第一阶段大家都成功了,就什么也不做.

如果第一阶段有失败的,那么他会反向做一个补偿逻辑去回滚.  这里确实和 tcc 优点像,但不完全一样,因为  tcc 再第一阶段中不是处理事务,只是做资源预留.

比如 扣余额业务,TCC 就直接冻结了,而 saga 是直接把余额扣掉了,如果 saga 第一阶段出现问题,第二阶段就是把扣掉的余额增加回来,实现回滚逻辑的.

1.2.2、saga 模式优缺点

缺点:

没有隔离性:因为一二阶段既没有全局锁,也没有预留资源,所有事务与事务之间可能存在脏写问题.

软状态持续时间不确定:saga 模式是按顺序执行每一个事务,如果有任何一个出现问题,就会立刻反向补偿. 因此这个不一致的时间不确定.

优点:

吞吐能力高:基于事件驱动实现异步调用,也就是一个事务完成了,自己执行下一个事务,无需阻塞等待.

性能高:第一阶段无需上锁,性能高.

实现简单:不用像 TCC 那样编写三个阶段,实现简单.

1.2.3、补充说明

Ps:由于这种模式的使用场景极少,因此就不演示了.

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

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

相关文章

MySQL数据库基础回顾与复习一

MySQL数据库 一、原理定义概念 定义 数据库(Database)是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库 数据库是长期储存在计算机内、有组织的、可共享的数据集合 分类: (1)非结构化数据: 数据相对来讲没…

Spring Cloud Gateway网关中各个过滤器的作用与介绍

文章目录 1. Route To Request URL Filter(路由过滤器)2. Gateway Filter(全局过滤器)3. Pre Filter(前置过滤器)4. Post Filter(后置过滤器)5. Error Filter(错误过滤器…

【刷题笔记10.6】LeetCode:汉明距离

LeetCode:汉明距离 一、题目描述 两个整数之间的汉明距离是指这两个数字对应二进制位不同的位置的数目。 给你两个整数x 和 y,计算并返回他们之间的汉明距离。 二、分析及代码实现 对于汉明距离问题我们其实可以将其转换为:计算x 和 y按…

U盘作为启动盘安装苹果OS X操作系统

如何制作 macOS USB启动盘?如何创建可引导的 macOS 安装器?接下来就为大家带来可引导的苹果电脑 macOS 系统U盘启动盘制作教程。U盘是我们在工作和生活中的好帮手,能储存和传递数据文件,重要的是,U盘还可以制作成苹果电…

leetcode - 365周赛

一&#xff0c;2873.有序三元组中的最大值 I ​ 该题的数据范围小&#xff0c;直接遍历&#xff1a; class Solution {public long maximumTripletValue(int[] nums) {int n nums.length;long ans 0;for(int i0; i<n-2; i){for(int ji1; j<n-1; j){for(int kj1; k<…

矩阵键盘的扫描原理与基础应用

基础知识 原理图 首先需要先将 J5 跳帽放到1和2之间。 表示选择的是矩阵键盘。 简化原理图 扫描原理&#xff1a; 以左上角按键为例。 先向 R1 输出低电平&#xff0c;向 R2&#xff0c;R3&#xff0c;R4 输出高电平。 再然后向 C1&#xff0c;C2&#xff0c;C3&#xff…

在Linux中软链接和硬链接的区别是什么?

2023年10月6日&#xff0c;周五晚上 目录 软链接(SymbolicLink):硬链接(HardLink):区别: 软链接(SymbolicLink): 软链接本身只是一个指向其他文件或目录的指针,不占用任何磁盘空间。软链接的修改或删除不会影响原文件。软链接可以指向不同文件系统中的文件。 硬链接(HardLink…

Cookie和Session详解以及结合生成登录效果

目录 引言 1.Cookie中的数据从哪来数据长啥样&#xff1f; 2.Cookie有什么作用&#xff1f; 3.cookie与session的工作关联&#xff1f; 4.Cookie到哪去&#xff1f; 5.Cookie如何存&#xff1f; 6.Session 7.Cookie与Session的关联与区别 8.通过代码理解 8.1 相关代码 8.2…

c++学习之 继承的方式

在C中&#xff0c;继承方式&#xff08;或继承访问权限&#xff09;有三种&#xff1a;public、protected 和 private&#xff0c;它们决定了派生类&#xff08;子类&#xff09;对基类&#xff08;父类&#xff09;成员的访问权限&#xff0c;它们之间的区别如下&#xff1a; …

局部放电发生因素与局部放电试验的重要性

局部放电发生的几个因素&#xff1a;   ①电场过于集中于某点&#xff1b;   ②固体介质有气泡&#xff0c;有害杂质未除净&#xff1b;   ③油中含水、含气、有悬浮微粒&#xff1b;   ④不同的介质组合中&#xff0c;在界面处有严重的电场畸变。   局部放电试验的重…

【小工具-生成合并文件】使用python实现2个excel文件根据主键合并生成csv文件

1 小工具说明 1.1 功能说明 一般来说&#xff0c;我们会先有一个老的文件&#xff0c;这个文件内容是定制好相关列的表格&#xff0c;作为每天的报告。 当下一天来的时候&#xff0c;需要根据新的报表文件和昨天的报表文件做一个合并&#xff0c;合并的时候就会出现有些事新增…

信息学奥赛一本通-编程启蒙3330:【例56.1】 和为给定数

3330&#xff1a;【例56.1】 和为给定数 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 625 通过数: 245 【题目描述】 现给出若干个整数&#xff0c;询问其中是否有一对数的和等于给定的数。 【输入】 共三行&#xff1a; 第一行是整数nn(0<n≤100,000)&…

指数分布优化器(EDO)(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

局部放电发生的现象特点以及解决方案

局部放电发生的现象特点&#xff1a;   1、局部放电是局部过热&#xff0c;电器元件和机械元件老化的预兆&#xff1b;   2、局部放电趋势是局放随着时间的上升指数&#xff0c;这是个曲折的过程&#xff0c;某个阶段可能下降&#xff0c;但某个阶段上升&#xff1b;   3…

C# - Opencv应用(1) 之VS下环境配置详解

C# - Opencv应用&#xff08;1&#xff09; 之VS下环境配置详解 有时候&#xff0c;单纯c#做前端时会联合C实现的dll来落地某些功能由于有时候会用C - Opencv实现算法后封装成dll&#xff0c;但是有时候会感觉麻烦&#xff0c;不如直接通过C#直接调用Opencv在此慢慢总结下C# -…

练[极客大挑战 2019]RCE ME

[极客大挑战 2019]RCE ME 文章目录 [极客大挑战 2019]RCE ME掌握知识解题思路关键paylaod 掌握知识 ​ RCE无数字和字母的bypass&#xff0c;取反 异或 递增 解题思路 打开题目链接&#xff0c;发现是代码审计的题目&#xff0c;而且代码比较简单&#xff0c;似乎关键就是RC…

一个很愚蠢的游戏(中)!!!

系列文章目录 c小游戏_睡觉觉觉得的博客-CSDN博客一个很愚蠢的游戏(上)&#xff01;&#xff01;&#xff01;_睡觉觉觉得的博客-CSDN博客 文章目录 系列文章目录前言一、个人名片二、描述三、代码1.代码 总结 前言 无 &#xff08;嘻嘻&#xff09; 一、个人名片 个人主页&a…

[NewStarCTF 2023 公开赛道] week1

最近没什么正式比赛&#xff0c;都是入门赛&#xff0c;有moectf,newstar,SHCTF,0xGame都是漫长的比赛。一周一堆制。 这周newstar第1周结束了&#xff0c;据说py得很厉害&#xff0c;第2周延期了&#xff0c;什么时候开始还不一定&#xff0c;不过第一周已经结束提交了&#…

python --在2x2的子图中绘制三个子图,并使第三个子图居中

python – 在2x2的子图中绘制三个子图&#xff0c;并使第三个子图居中 基于python&#xff0c;绘制一个2x2的子图范围&#xff0c;但是只显示3个子图&#xff0c;并使得第三个子图居中显示’ 思路&#xff1a; 建立一个2x2的子图前两个正常画&#xff0c;其中第三个子图跨越两…

[开源项目推荐]privateGPT使用体验和修改

文章目录 一.跑通简述二.解读ingest.py1.导入库和读取环境变量2.文档加载3.文档处理&#xff08;调用文件加载函数和文本分割函数&#xff09; 三.injest.py效果演示1.main函数解读2.测试 四.修改代码&#xff0c;使之适配多知识库需求1.修改配置文件&#xff1a;constants.py2…