Spring 事务原理总结六

不知不觉,关于Spring事务的文章已经写了五篇了。老实讲我自己不断质疑过自己:现在写这些文章还有意义吗?当前的市场已经成什么样了,为什么还要固守这落后的技术?但是贝索斯一次接受访谈的回答,让我写下去的决心更加坚定了,他是这样说的:相较于千变万化的事物,我更关注那些恒久不变的东西!

书归正传,上篇文章我们解决了《Spring事务原理总结四》这篇文章中提到的几个问题中的三个,其中“Spring事务异常回滚执行流程”这个问题,我们并没有梳理。今天就借这篇文章详细梳理一下。如果各位觉得这些文章对您有用,还请多多关注,谢谢!如果大家觉得有哪些地方梳理的不正确,也请大家多多指教,非常感谢!本篇文章梳理的比较啰嗦,大家可以跳过中间过程,看最后的总结。如果有些地方大家觉得不对,欢迎指出。

执行流程梳理

继续采用《Spring事务原理总结一》中的案例,修改TransferServiceImpl类中的check(String, String, BigDecimal)方法,具体代码如下所示:

@Override
public void check(String from, String to, BigDecimal money) {

    System.out.println("校验开始");
    System.out.println("校验中||...........");
    try {
        System.out.println(1 / 0);
        Thread.sleep(1000 * 5);
    } catch (InterruptedException e) {
    }
    System.out.println("校验中==...........");
    System.out.println("校验结束");

}

启动程序(用debug模式运行SpringTransactionApplication类即可),接着会在TransactionAspectSupport类的invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation)方法中的断点处停下,具体如下图所示:

启动程序(用debug模式运行SpringTransactionApplication类即可),接着会在TransactionAspectSupport类的invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation)方法中的断点处停下,具体如下图所示:

接着让我们继续执行代码,直到程序执行到下图所示的断点处停下,详情情况请参见下面这幅图:

这里需要注意一下,控制台并未输出TransferServiceImpl#check(String, String, BigDecimal)方法中要打印的任何内容,然后继续执行,结果如下图所示:

由图中可以看出,控制台输出了TransferServiceImpl#check(String, String, BigDecimal)方法要打印的内容,并且程序直接进入了catch逻辑。仔细观察会发现这个异常类型为java.lang.ArithmeticException: / by zero,这就是我们在代码中添加的System.out.println(1 / 0)抛出的,如果这个方法实际操作的是数据库,那catch逻辑中要执行的就是回滚操作了。先来看一下这个方法(这个方法——completeTransactionAfterThrowing(TransactionInfo, Throwable)——位于TransactionAspectSupport类中)的源码,如下所示:

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
       if (logger.isTraceEnabled()) {
          logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                "] after exception: " + ex);
       }
       if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
          try {
             txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
          }
          catch (TransactionSystemException ex2) {
             logger.error("Application exception overridden by rollback exception", ex);
             ex2.initApplicationException(ex);
             throw ex2;
          }
          catch (RuntimeException | Error ex2) {
             logger.error("Application exception overridden by rollback exception", ex);
             throw ex2;
          }
       }
       else {
          // We don't roll back on this exception.
          // Will still roll back if TransactionStatus.isRollbackOnly() is true.
          try {
             txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
          }
          catch (TransactionSystemException ex2) {
             logger.error("Application exception overridden by commit exception", ex);
             ex2.initApplicationException(ex);
             throw ex2;
          }
          catch (RuntimeException | Error ex2) {
             logger.error("Application exception overridden by commit exception", ex);
             throw ex2;
          }
       }
    }
}

先来看一下下面这幅运行时图片,程序运行到if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex))处停下,具体见下图:

先让我们一起看一下txInfo.transactionAttribute.rollbackOn(ex)这句,这段代码的详细执行流程为:

  1. 执行DelegatingTransactionAttribute#rollbackOn(Throwable ex),注意DelegatingTransaction-Attribute中持有一个TransactionAttribute对象
  2. 调用RuleBasedTransactionAttribute#rollbackOn(Throwable ex)
  3. 调用DefaultTransactionAttribute#rollbackOn(Throwable ex)

对于这个调用过程,我们需要注意以下几点:

  • DelegatingTransactionAttribute类中持有的TransactionAttribute对象的实际类型是RuleBaseTransactionAttribute,这个类的rollbackOn(Throwable)方法实际上是一个代理方法,其会把处理转发给RuleBaseTransactionAttribute这个实际类型中的rollbackOn(Throwable)方法。所以DelegatingTransactionAttribute类中的rollbackOn(Throwable)方法的源码非常简单,具体如下所示:
public boolean rollbackOn(Throwable ex) {
    return this.targetAttribute.rollbackOn(ex);
}
  • RuleBasedTransactionAttribute这个类的rollbackOn(Throwable)方法是实际进行判断的地方,其中有一个rollbackRules对象,该对象的类型是List,其中存储的是一个一个的RollbackRuleAttribute类型的对象,首先来看一下rollbackOn(Throwable)这个方法的源码吧:
public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;

    if (this.rollbackRules != null) {
       for (RollbackRuleAttribute rule : this.rollbackRules) {
          int depth = rule.getDepth(ex);
          if (depth >= 0 && depth < deepest) {
             deepest = depth;
             winner = rule;
          }
       }
    }

    // User superclass behavior (rollback on unchecked) if no rule matches.
    if (winner == null) {
       return super.rollbackOn(ex);
    }

    return !(winner instanceof NoRollbackRuleAttribute);
}

通过这段源码不难发现,程序首先会遍历本类持有的rollbackRules对象,从中找到适合的数据并赋值给winner;接着判断winner对象是否为空,如果winner对象为空,则直接调用父类的rollbackOn(Throwable)方法,判断当前的异常类型是否合法,否则判断当前的winner对象是否为NoRollbackRuleAttribute类型,并取反,然后将结果返回给上级调用者。下面让我们看一下RollbackRuleAttribute类的继承结构,具体如下图所示:

接下来让我们看一下RuleBasedTransactionAttribute的父类DefaultTransactionAttribute类中的rollbackOn(Throwable)方法的源码

@Override
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

这个方法的主要作用就是判断当前的异常类型是否为RuntimeException或Error,如果是这两个就返回true,否则就返回false

看到这里我不禁有个问题:RuleBasedTransactionAttribute对象中的rollbackRules对象中的值是从哪里来的?接着让我们改造以下TransferServiceImpl类上的@Transactional注解,在其中增加一个rollbackFor属性,具体如下图所示:

然后启动程序,查看结果(注意断点在RuleBasedTransactionAttribute#rollbackOn()方法中),具体如下图所示:

从图中不难发现此时rollbackRules对象中的值确实是我们通过rollbackFor属性注入的两个异常类。但我又有点好奇RuleBasedTransactionAttribute#rollbackOn(Throwable)方法中的最后一句“!(winner instanceof NoRollbackRuleAttribute)”中的NoRollbackRuleAttribute这个是从哪里来的?还记得@Transactional注解上的noRollbackFor属性吗?让我们继续改造TransferServiceImpl类上的@Transactional注解,在其上添加noRollbackFor属性,具体如下图所示:

然后重新启动程序,查看结果(注意断点在RuleBasedTransactionAttribute#rollbackOn()方法中),具体如下图所示:

从图中可以看出,我们在注解中指定的CustomException被包装成了NoRollbackRuleAttribute类型的对象,由于前面我们更改了TransferServiceImpl类的check()方法,其最终会抛出一个名为CustomException类型的异常,所以这段代码返回的结果是false,最终也就不会执行TransactionAspectSupport中的completeTransactionAfterThrowing(TransactionInfo, Throwable)方法。注意TransferServiceImpl类中的check()方法的源码为:

public void check(String from, String to, BigDecimal money) throws Exception {

    System.out.println("校验开始");
    System.out.println("校验中||...........");
    try {
        // System.out.println(1 / 0);
        Thread.sleep(1000 * 5);
        throw new CustomException();
    } catch (InterruptedException e) {
    }
    System.out.println("校验中==...........");
    System.out.println("校验结束");

抛开这些问题,继续回到DefaultTransactionAttribute#rollbackFor()方法中,最终程序抛出的ArithmeticException异常经过该方法后返回的结果为true。具体如下图所示:

总体来看在不指定@Transactional注解的rollbackFor属性的时候,调用RuleBasedTransact-ionAttribute#rollbackOn()方法的作用就是判断当前异常是否为运行时异常(即RuntimeException或者Error),如果是则触发后面的回滚逻辑,如果不是则不触发后面的回滚逻辑

接下来让我们继续回到TransactionAspectSupport#completeTransactionAfterThrowing(Tra-nsactionInfo, Throwable)方法中,经过前面的判断,最终代码走到了txInfo.getTransactionManag-er().rollback(txInfo.getTransactionStatus())这行,具体如下图所示:

首先来看一下TransactionManager类的rollback(TransactionStatus)方法的源码(实际代码位于AbstractPlatformTransactionManager类中):

public final void rollback(TransactionStatus status) throws TransactionException {
    if (status.isCompleted()) {
       throw new IllegalTransactionStateException(
             "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }

    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    processRollback(defStatus, false);
}

接着再来看一下processRollback()方法的源码,其主要作用就是执行真正的回滚逻辑。下面一起看一下processRollback()方法的源码:

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
       boolean unexpectedRollback = unexpected;
       boolean rollbackListenerInvoked = false;

       try {
          triggerBeforeCompletion(status);

          if (status.hasSavepoint()) {
             if (status.isDebug()) {
                logger.debug("Rolling back transaction to savepoint");
             }
             this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
             rollbackListenerInvoked = true;
             status.rollbackToHeldSavepoint();
          }
          else if (status.isNewTransaction()) {
             if (status.isDebug()) {
                logger.debug("Initiating transaction rollback");
             }
             this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
             rollbackListenerInvoked = true;
             doRollback(status);
          }
          else {
             // Participating in larger transaction
             if (status.hasTransaction()) {
                if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                   if (status.isDebug()) {
                      logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                   }
                   doSetRollbackOnly(status);
                }
                else {
                   if (status.isDebug()) {
                      logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                   }
                }
             }
             else {
                logger.debug("Should roll back transaction but cannot - no transaction available");
             }
             // Unexpected rollback only matters here if we're asked to fail early
             if (!isFailEarlyOnGlobalRollbackOnly()) {
                unexpectedRollback = false;
             }
          }
       }
       catch (RuntimeException | Error ex) {
          triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
          if (rollbackListenerInvoked) {
             this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, ex));
          }
          throw ex;
       }

       triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
       if (rollbackListenerInvoked) {
          this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, null));
       }

       // Raise UnexpectedRollbackException if we had a global rollback-only marker
       if (unexpectedRollback) {
          throw new UnexpectedRollbackException(
                "Transaction rolled back because it has been marked as rollback-only");
       }
    }
    finally {
       cleanupAfterCompletion(status);
    }
}

通过源码不难发现该方法接收一个TransactionStatus对象作为参数,这个对象封装了当前事务的状态信息。当需要回滚事务时(例如遇到未捕获异常或者显式调用TransactionTemplate或PlatformTransactionManager的rollback()方法时),框架会调用此方法来完成以下任务

  1. 清理资源:根据事务的具体类型(如JDBC、Hibernate、JTA等)清理与事务相关的一些资源,这可能包括数据库连接的回滚操作或者其他事务性资源的相应清理工作
  2. 更新事务状态:将事务状态标记为已回滚,确保后续不会尝试提交这个事务
  3. 触发监听器或回调:如果有注册的事务同步监听器(TransactionSynchronizationAdapter),则会触发相应的 afterCompletion 回调方法,通知它们事务已经回滚

总之,processRollback方法实现了事务生命周期中的“回滚”阶段,确保事务能够按照预期进行回滚,从而维持事务的原子性和一致性。通过debug跟踪和阅读源码,我们发现本示例最终走到了elsle if分支,该逻辑片段最终会调用DatasourceTransactionManager类的doRollback(DefaultTransactionStatus)方法,先来看一下这个方法的源码吧,具体如下所示:

protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
       logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    }
    try {
       con.rollback();
    }
    catch (SQLException ex) {
       throw translateException("JDBC rollback", ex);
    }
}

通过源码,我们可以很清晰的看到,其最终就是通过调用Connection对象上的rollback()方法来完成事务的回滚的。

总结

文章进行到这里,前面遗留的问题基本上就梳理完了。首先通过这篇文章我们可以很清晰的看到Spring的设计者利用动态代理(cglib动态代理)及各种设计模式(责任链、模板等设计模式,其中模板设计模式在AbstractPlatformTransactionManager类体现的最为明显。该类中的rollback(TransactionStatus)方法规定了调用流程,即调用本类的processRollback(DefaultTransactionStatus, boolean)方法,而该方法又继续调用了本类中的模板方法doRollback(DefaultTransactionStatus),实际上调用的是其实现类中的方法完成了事务逻辑的抽离,使开发者可以花费更多的精力在业务代码的编写上。下面就让我们一起看一下AbstractPlatformTransactionManager类中的这几个方法的源码:

public final void rollback(TransactionStatus status) throws TransactionException {
    if (status.isCompleted()) {
       throw new IllegalTransactionStateException(
             "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }

    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    processRollback(defStatus, false);
}
// 
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
       boolean unexpectedRollback = unexpected;
       boolean rollbackListenerInvoked = false;

       try {
          triggerBeforeCompletion(status);

          if (status.hasSavepoint()) {
             if (status.isDebug()) {
                logger.debug("Rolling back transaction to savepoint");
             }
             this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
             rollbackListenerInvoked = true;
             status.rollbackToHeldSavepoint();
          }
          else if (status.isNewTransaction()) {
             if (status.isDebug()) {
                logger.debug("Initiating transaction rollback");
             }
             this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
             rollbackListenerInvoked = true;
             doRollback(status);
          }
          else {
             // Participating in larger transaction
             if (status.hasTransaction()) {
                if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                   if (status.isDebug()) {
                      logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
                   }
                   doSetRollbackOnly(status);
                }
                else {
                   if (status.isDebug()) {
                      logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
                   }
                }
             }
             else {
                logger.debug("Should roll back transaction but cannot - no transaction available");
             }
             // Unexpected rollback only matters here if we're asked to fail early
             if (!isFailEarlyOnGlobalRollbackOnly()) {
                unexpectedRollback = false;
             }
          }
       }
       catch (RuntimeException | Error ex) {
          triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
          if (rollbackListenerInvoked) {
             this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, ex));
          }
          throw ex;
       }

       triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
       if (rollbackListenerInvoked) {
          this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, null));
       }

       // Raise UnexpectedRollbackException if we had a global rollback-only marker
       if (unexpectedRollback) {
          throw new UnexpectedRollbackException(
                "Transaction rolled back because it has been marked as rollback-only");
       }
    }
    finally {
       cleanupAfterCompletion(status);
    }
}
// 
protected abstract void doRollback(DefaultTransactionStatus status) throws TransactionException;

下面再回顾一下AbstractPlatformTransactionManager的实现类DataSourceTransactionManager中的doRollback()方法的源码(如果向了解这两个类的继承关系,可以浏览《Spring 事务原理总结三》这篇文章)

protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
       logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    }
    try {
       con.rollback();
    }
    catch (SQLException ex) {
       throw translateException("JDBC rollback", ex);
    }
}

接着通过本章强化了我们对@Transactional注解的认识,该注解上的rollbackFor属性可以指定哪些异常发生时需要执行回滚操作,该注解上的noRollbackFor属性则可以指定哪些异常发生时不需要执行回滚操作(Spring设计者的这个设计,为开发者在开发中按照业务异常分别处理异常,提供了很大的便利)。另外通过本章我们也知道了通过这两个属性指定的异常最终会被分别包装成RollbackRuleAttribute和No RollbackRuleAttribute类型的对象,程序执行时会通过RuleBasedTransactionAttribute中的rollbackOn(Throwable ex)方法进行区分并加以判断,具体判断代码如下所示(含DelegatingTransactionAttribute和RuleBasedTransactionAttribute的父类DefaultTransactionAttribute中的rollbackOn(Throwable)方法):

/ DelegatingTransactionAttribute类中的rollbackOn(Throwable)方法
public boolean rollbackOn(Throwable ex) {
    return this.targetAttribute.rollbackOn(ex);
}
// RuleBasedTransactionAttribute类中的rollbackOn(Throwable)方法
public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;

    if (this.rollbackRules != null) {
       for (RollbackRuleAttribute rule : this.rollbackRules) {
          int depth = rule.getDepth(ex);
          if (depth >= 0 && depth < deepest) {
             deepest = depth;
             winner = rule;
          }
       }
    }

    // User superclass behavior (rollback on unchecked) if no rule matches.
    if (winner == null) {
       return super.rollbackOn(ex);
    }

    return !(winner instanceof NoRollbackRuleAttribute);
}
// RuleBasedTransactionAttribute的父类DefaultTransactionAttribute中的rollbackOn(Throwable)方法
@Override
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(1)发现与明确问题

抱歉&#xff0c;过春节这几天&#xff0c;没有更新。赶紧续上。 人就是这样&#xff0c;放假之前呢&#xff0c;想着趁着这个假期&#xff0c;把很多之前没有做好的事情&#xff0c;都梳理好&#xff0c;该补的也补上&#xff0c;结果一个假期就这样过去了&#xff0c;很多想…

MATLAB知识点:uniquetol函数(★★☆☆☆)考虑了一定的容差的unique函数

讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章&#xff1a;课后习题讲解中拓展的函数 在讲解第三…

Nginx高级课程扩容(四)

Brotli 安装 ● 官网 ● https://github.com/google/ngx_brotli ● https://codeload.github.com/google/brotli/tar.gz/refs/tags/v1.0.9 ● 下载 两个项目 ● 解压缩模块化编译 ./configure --with-compat --add-dynamic-module/root/ngx_brotli-1.0.0rc --prefix/usr/local…

Open CASCADE学习|布尔运算后消除内部拓扑

在CAD建模中&#xff0c;布尔运算是一种逻辑运算方法&#xff0c;通过这种方法&#xff0c;可以创建、修改或组合几何对象。布尔运算主要包括并集&#xff08;UNION&#xff09;、交集&#xff08;INTERSECT&#xff09;和差集&#xff08;SUBTRACT&#xff09;三种运算。 并集…

数学实验第三版(主编:李继成 赵小艳)课后练习答案(十三)(2)

实验十三&#xff1a;数据拟合与数据差值 练习二 1.在飞机的机翼加工时,由于机翼的尺寸很大,所以通常在图纸上只能标出部分关键点的尺寸某型号飞机的机翼上缘轮廓线的部分数据如下: x 0 4.74 9.05 19 38 76 95 114 133 152 171 190 y 0 5.23 8.1 11.97 16.…

《Go 简易速速上手小册》第10章:微服务与云原生应用(2024 最新版)

文章目录 10.1 构建微服务架构 - 探索 Go 语言的微观世界10.1.1 基础知识讲解10.1.2 重点案例&#xff1a;订单处理系统订单服务测试服务 10.1.3 拓展案例 1&#xff1a;用户认证服务安装所需的包实现用户模型和存储实现 JWT 生成和验证实现认证服务测试服务 10.1.4 拓展案例 2…

如何清除谷歌浏览器的缓存?这里有详细步骤

如果你想解决加载或格式化问题&#xff0c;以改善你在谷歌Chrome上的浏览体验&#xff0c;那么清除缓存和cookie是一个很好的开始。以下是删除它们的方式和操作。 删除缓存和cookie时会发生什么 当你访问一个网站时&#xff0c;它有时会保存&#xff08;或记住&#xff09;某…

数据结构第十六天(二叉树层序遍历/广度优先搜索(BFS)/队列使用)

目录 前言 概述 接口 源码 测试函数 运行结果 往期精彩内容 前言 从前的日色变得慢&#xff0c;车&#xff0c;马&#xff0c;邮件都慢&#xff0c;一生,只够爱一个人。 概述 二叉树的层序遍历可以使用广度优先搜索&#xff08;BFS&#xff09;来实现。具体步骤如下&…

第11章 GUI

11.1 Swing概述 Swing是Java语言开发图形化界面的一个工具包。它以抽象窗口工具包&#xff08;AWT&#xff09;为基础&#xff0c;使跨平台应用程序可以使用可插拔的外观风格。Swing拥有丰富的库和组件&#xff0c;使用非常灵活&#xff0c;开发人员只用很少的代码就可以创建出…

[嵌入式系统-28]:开源的虚拟机监视器和仿真器:QEMU(Quick EMUlator)与VirtualBox、VMware Workstation的比较

目录 一、QEMU概述 1.1 QEMU架构 1.2 QEMU概述 1.3 什么时候需要QEMU 1.4 QEMU两种操作模式 1.5 QEMU模拟多种CPU架构 二、QEMU与其他虚拟机的比较 2.1 常见的虚拟化技术 2.1 Linux KVM 2.2 Windows VirtualBox 2.3 Windows VMware workstation 三、VirtualBox、VM…

21种matlab信号分解方法汇总

21中信号分解方法汇总 CEEMD(互补集合经验模态分解)CEEMDAN(自适应噪声完备集合经验模态分解) EEMD(集合经验模态分解&#xff09;EMD(经验模态分解)ESMD(极点对称模态分解&#xff09;EWT(经验小波变换分解)FEEMD(快速EEMD分解)ICEEMDAN(改进自适应噪声完备集合经验模态分解)L…

自然语言编程系列(三):自然语言编程工具

自然语言编程工具尝试让用户以更接近日常对话的方式描述任务&#xff0c;然后将其自动转换成合适的代码。 自然语言编程工具&#xff08;Natural Language Programming, NLP&#xff09;旨在降低编程门槛&#xff0c;使得不具备传统编程技能的用户能够以他们习惯的日常对话方式…

Python中超超超高颜值的库,我刚发现的...

在Python中&#xff0c;有一个名为rich的宝藏包&#xff0c;它能够将你的终端输出变成一场视觉盛宴。rich是一个用于在终端中呈现富文本&#xff08;包括颜色、样式、表格、进度条等&#xff09;的Python库&#xff0c;它可以使你的命令行界面变得生动而富有表现力。 如何安装 …

计算机网络-数据通信基础

目录 前言 一、数据通信基本概念 二、数据通信相关知识1 总结 前言 正在学习计算机网络体系&#xff0c;把每日所学的知识梳理出来&#xff0c;既能够当作读书笔记&#xff0c;又能分享出来和大家一同学习讨论。 一、数据通信基本概念 基本概念&#xff1a;信源、信道、信宿&…

数据集合

目录 并集 union union all 区别 交集 intersect 差集 minus 错误操作 Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 常用的数学集合有&#xff1a;交集、并集、差集、补集 每一次查询实际上都会返回数据集合&#xff0c;…

浅析太阳能电池量子效率测试系统的主要组成部分

太阳能电池量子效率测试系统是用于对太阳能电池进行量子效率测试的设备。量子效率是指太阳能电池在接收光照射时&#xff0c;将光子转化为电子的效率。太阳能电池的量子效率越高&#xff0c;其转化光能为电能的效率就越高。主要由以下几个组成部分构成&#xff1a; 光源&#x…

测试物理网络的ping命令

通过发送Internet控制消息协议&#xff08;ICMP&#xff09;并接收其应答&#xff0c;测试验证与另一台TCP/IP计算机的IP级联通性、可达到性和名称解析的疑难问题主要TCP/IP命令。如果不带参数&#xff0c;ping将显示帮助。通过在命令提示符下输入“ping /&#xff1f;”命令&a…

生成式 AI - Diffusion 模型 (DDPM)原理解析(1)

来自 论文《 Denoising Diffusion Probabilistic Model》&#xff08;DDPM&#xff09; 论文链接&#xff1a;https://arxiv.org/abs/2006.11239 Hung-yi Lee 课件整理 简单地介绍diffusion model 的基本概念&#xff0c;diffusion model有很多不同的变形&#xff0c;现在比较…

Open CASCADE学习|分割

目录 1、添加头文件与源文件 GEOMAlgo_Splitter.h GEOMAlgo_Splitter.cpp 2、测试 2.1平面分割立方体 2.2以边分面 2.3以面分面 1、添加头文件与源文件 GEOMAlgo_Splitter.h // Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE//// Copyright (C) 2003-2…

第三十三天| 1005.K次取反后最大化的数组和、134. 加油站 、135. 分发糖果

Leetcode 1005.K次取反后最大化的数组和 题目链接&#xff1a;1005 K次取反后最大化的数组和 题干&#xff1a;给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可…