Spring 事务和事务传播机制
Spring 事务和事务传播机制
一、Spring 事务的基本概念
事务是一组操作,被视为一个不可分割的工作单元,要么全部完成,要么全部失败回滚,以此来确保数据的一致性和完整性。Spring事务管理允许我们在应用程序中声明式地或编程式地管理事务,它提供了一个事务管理抽象层,使得事务的使用和配置更加简单和灵活。
Spring事务管理不直接管理数据库事务,而是通过委托给底层的数据库事务管理器,如JDBC或Hibernate的事务管理器,来实现对数据库事务的控制。Spring事务管理分为编码式和声明式的两种方式。
- 编程式事务:通过编码方式实现事务。
- 声明式事务:基于AOP,即使用@Transactional注解,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染,因此在实际使用中声明式事务用的比较多。
通过简单的配置或注解,Spring允许开发者将事务管理从业务代码中分离出来,提高了代码的可读性和可维护性。使用@Transactional注解,简单配置即可管理事务。例如,在Service层的方法上标注@Transactional注解,Spring将自动处理事务边界。
使用TransactionTemplate或PlatformTransactionManager手动管理事务,虽然不常用,但在某些情况下,可以用于需要更细粒度控制的场景。
值得注意的是,Spring利用AOP和事务拦截器来拦截被@Transactional注解的方法,在方法调用前开启事务,在方法调用后根据方法执行结果决定提交或回滚事务。
此外,在某些情况下,@Transactional注解可能会失效,包括:
-
方法是非public的,因为事务的底层是利用cglib代理实现,cglib是基于父子类来实现的,子类是不能重载父类的private方法,所以无法很好利用代理。
-
使用的数据库引擎不支持事务,因为Spring的事务调用的也是数据库事务的API,如果数据库都不支持事务,那么@Transactional注解也就失效了。
-
添加了@Transactional注解的方法不能在同一个类中调用,否则会使事务失效。这是因为Spring AOP通过代理来管理事务,自调用不会经过代理。
-
@Transactional注解属性propagation设置错误,若是错误的配置以下三种propagation,事务将不会发生回滚:
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
-
@Transactional注解属性rollbackFor设置错误,rollbackFor可以指定能够触发事务回滚的异常类型。默认情况下,Spring仅在抛出未检查异常(继承自RuntimeException)时回滚事务。对于受检异常(继承自Exception),事务不会回滚,除非明确配置了rollbackFor属性。
-
异常被捕获了,导致@Transactional失效。当事务方法中抛出一个异常后,应该是需要表示当前事务需要rollback,如果在事务方法中手动捕获了该异常,那么事务方法则会认为当前事务应该正常提交,此时就会出现事务方法中明明有报错信息表示当前事务需要回滚,但是事务方法认为是正常,出现了前后不一致,也会因此抛出UnexpectedRollbackException异常。
二、Spring 事务的传播机制
事务的传播机制是Spring事务管理中的核心概念之一。在多个包含事务的方法里相互调用时,它们之间是如何扩散或者传递的,就是事务的传播机制。这个机制保证了一个事务在多个调用方法之间的可控性(稳定性)。
Spring框架中,事务传播机制是指在一个事务方法调用另一个事务方法时,Spring如何管理这些方法之间的事务边界。Spring提供了七种事务传播行为,以满足不同的业务需求。
-
REQUIRED:这是最常用的事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这种行为确保所有事务操作都在一个统一的事务上下文中执行。适用场景是大多数情况下使用此传播行为,确保多个事务操作在同一个事务中执行,以保持数据一致性。
如果外层方法没有事务管理,那么调用事务方法的外层方法没有被事务注解(如@Transactional)标记,在调用事务方法时,当前就没有事务存在。例如,如果方法A没有事务管理,方法B被标记为@Transactional,当调用方法A时,方法A没有事务管理,因此当前没有事务。当方法A调用方法B时,由于方法A没有事务,所以方法B会创建一个新的事务。如果将方法A也标记为@Transactional,那么方法A开启了一个事务,因此当前有事务。当方法A调用方法B时,方法B会加入方法A的事务,而不是创建新的事务。
-
SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。这种传播行为适用于既能在事务内执行,也能在事务外执行的操作。比如,某些只读操作或性能要求不高的操作。
-
MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。这种传播行为适用于必须在现有事务中执行的操作。通常用于一些关键业务逻辑,要求调用者必须在事务中运行。
-
REQUIRES_NEW:总是启动一个新的事务。如果当前存在事务,则将当前事务挂起。在新的事务执行完成后,恢复先前的事务。这种传播行为适用于需要独立事务的情况,例如记录日志或审计信息,不希望这些操作受到主事务的影响。
-
NOT_SUPPORTED:以非事务方式执行操作。如果当前存在事务,则将当前事务挂起。这种传播行为适用于不需要事务支持的操作,或某些性能要求高、不希望受到事务管理开销影响的操作。
-
NEVER:以非事务方式执行。如果当前存在事务,则抛出异常。这种传播行为适用于明确不希望在事务中执行的操作。比如,某些数据库操作可能不支持事务。
-
NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前不存在事务,则等价于REQUIRED,即创建一个新的事务。嵌套事务依赖于底层数据库对保存点(savepoint)的支持。这种传播行为适用于需要部分提交或回滚的复杂业务操作。比如,复杂的财务操作,某些步骤失败后需要回滚到特定点。
下面通过一个具体的例子来说明事务传播机制的作用:
public class MyService {public void methodA() {// 非事务代码methodB(); // 调用有事务管理的方法// 继续执行非事务代码}@Transactionalpublic void methodB() {// 有事务管理的代码// 执行数据库操作}
}
在这个例子中,methodA开始执行时,此时没有事务。当methodA调用methodB时,由于methodB被标记为@Transactional,Spring会为methodB创建一个新的事务。methodB在事务中执行其代码(如数据库操作)。methodB执行完成后,事务提交或回滚(取决于方法执行的结果和异常情况)。methodB返回到methodA,此时事务已经结束。methodA继续执行剩余代码,但此时已经没有事务。所以,在methodA中,methodB执行的部分是在事务中的,但methodB返回后,methodA剩余的代码是不在事务中的。事务边界由methodB的开始和结束决定,事务结束后事务上下文不再存在。
三、事务传播机制的组合和策略
在实际应用中,可能会遇到多种事务传播行为的组合使用。理解这些组合的行为对于正确设计事务管理策略至关重要。
- REQUIRED-REQUIRED:如果A方法在事务中运行,则B方法将继承A方法的事务。如果A方法没有事务,则B方法将在一个新的事务中运行。
- REQUIRED-SUPPORTS:如果A方法在事务中运行,则B方法将继承A方法的事务。如果A方法没有事务,则B方法将以非事务方式运行。
- REQUIRED-MANDATORY:如果A方法在事务中运行,则B方法将继承A方法的事务。如果A方法没有事务,则B方法将抛出异常。
- REQUIRED-REQUIRES_NEW:无论A方法是否在事务中运行,B方法都会开启一个新的事务并在该事务中运行。
- REQUIRED-NOT_SUPPORTED:如果A方法在事务中运行,则B方法将以非事务方式运行。如果A方法没有事务,则B方法也将以非事务方式运行。
- REQUIRED-NEVER:如果A方法在事务中运行,则B方法将抛出异常。如果A方法没有事务,则B方法将以非事务方式运行。
- REQUIRED-NESTED:如果A方法在事务中运行,则B方法将作为A方法的嵌套事务运行。如果A方法没有事务,则B方法将在一个新的事务中运行。
类似的,还可以根据其他传播行为组合出更多的策略。在实际应用中,需要根据具体的业务需求来选择合适的事务传播行为组合。
四、事务隔离级别
事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度。当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:
- 脏读:一个事务读取了另一个事务未提交的更改。
- 不可重复读:在同一个事务中,两次读取同一数据的结果不一致。
- 幻读:一个事务读取了另一个事务插入的数据。
Spring事务管理框架支持标准的数据库事务隔离级别,这些隔离级别与底层数据库系统所支持的事务隔离级别
为了处理上述的并发问题,数据库系统定义了四种标准的事务隔离级别,Spring事务管理框架也支持这些隔离级别。以下是四种标准的事务隔离级别:
-
READ_UNCOMMITTED(读取未提交):
- 允许读取未提交的数据。
- 可能会发生脏读、不可重复读和幻读。
- 性能较高,但数据一致性最差。
-
READ_COMMITTED(读取已提交):
- 只能读取已提交的数据。
- 避免脏读,但可能会发生不可重复读和幻读。
- 大多数数据库系统的默认隔离级别。
-
REPEATABLE_READ(可重复读):
- 保证在同一个事务中多次读取同一数据时,结果一致。
- 避免脏读和不可重复读,但可能会发生幻读(在某些数据库系统中,如MySQL的InnoDB引擎,通过间隙锁可以避免幻读)。
- MySQL的默认隔离级别(在InnoDB引擎下,实际上通过额外的机制达到了SERIALIZABLE的一部分效果,即避免了幻读)。
-
SERIALIZABLE(串行化):
- 通过强制事务串行执行,避免脏读、不可重复读和幻读。
- 数据一致性最好,但性能最差,因为事务需要等待其他事务完成才能继续执行。
在Spring中,可以通过@Transactional注解的isolation属性来设置事务的隔离级别。例如:
@Transactional(isolation = Isolation.SERIALIZABLE)
public void myTransactionalMethod() {// 方法体
}
需要注意的是,事务隔离级别的选择应该根据具体的应用场景和性能需求来决定。较高的隔离级别可以提供更好的数据一致性,但可能会牺牲性能;较低的隔离级别可以提供更好的性能,但可能会牺牲数据一致性。
五、Spring事务的超时设置
除了隔离级别外,Spring事务管理还提供了超时设置,用于控制事务的最大执行时间。如果事务在指定的时间内没有完成,那么事务将被自动回滚。
在Spring中,可以通过@Transactional注解的timeout属性来设置事务的超时时间。例如:
@Transactional(timeout = 30) // 设置超时时间为30秒
public void myTransactionalMethod() {// 方法体
}
需要注意的是,超时时间的单位是秒。如果设置为-1,则表示没有超时限制。
超时设置对于长时间运行的事务特别有用,可以避免因为某些原因(如死锁)导致事务无限期地等待下去。通过设置一个合理的超时时间,可以在一定程度上提高系统的健壮性和可用性。
六、Spring事务的回滚规则
在Spring事务管理中,事务的回滚通常是由异常触发的。当事务方法抛出一个运行时异常(RuntimeException)或错误(Error)时,默认情况下,Spring会回滚事务。此外,还可以通过@Transactional注解的rollbackFor和noRollbackFor属性来定制回滚规则。
rollbackFor:指定哪些异常类型会导致事务回滚。例如:
@Transactional(rollbackFor = {CustomException.class, AnotherException.class})
public void myTransactionalMethod() {// 方法体
}
在这个例子中,如果myTransactionalMethod方法抛出了CustomException或AnotherException异常,那么事务将被回滚。
noRollbackFor:指定哪些异常类型不会导致事务回滚。例如:
@Transactional(noRollbackFor = {BusinessException.class})
public void myTransactionalMethod() {// 方法体
}
在这个例子中,即使myTransactionalMethod方法抛出了BusinessException异常,事务也不会被回滚。
需要注意的是,rollbackFor和noRollbackFor属性可以同时使用,以定制更复杂的回滚规则。此外,如果事务方法抛出了一个受检异常(checked exception),并且没有通过rollbackFor属性指定该异常类型会导致事务回滚,那么默认情况下,事务将不会被回滚。这是因为受检异常通常是由编程错误或业务逻辑错误引起的,而不是由运行时环境或数据问题引起的。因此,在大多数情况下,不需要对受检异常进行回滚处理。
七、Spring事务的最佳实践
在使用Spring事务管理时,有一些最佳实践可以帮助开发者更好地管理事务和提高系统的健壮性和性能:
-
合理设置事务的传播行为:根据具体的业务需求和性能要求来选择合适的事务传播行为。避免不必要的事务嵌套和事务挂起操作。
-
合理设置事务的隔离级别:根据数据一致性和性能需求来选择合适的事务隔离级别。避免使用过高的隔离级别导致性能下降或使用过低的隔离级别导致数据不一致。
-
合理设置事务的超时时间:为长时间运行的事务设置一个合理的超时时间,以避免因为某些原因(如死锁)导致事务无限期地等待下去。
-
定制回滚规则:根据具体的业务需求来定制事务的回滚规则。对于不需要回滚的异常类型,可以使用
noRollbackFor属性来避免不必要的回滚操作。 -
避免大事务:尽量避免在单个事务中执行过多的数据库操作或处理过多的数据。大事务可能会导致性能下降、死锁等问题。如果必须处理大量数据或执行多个数据库操作,可以考虑将它们拆分成多个小事务来处理。
-
使用合适的数据库连接池:配置一个合适的数据库连接池来管理数据库连接资源。通过合理的连接池配置可以提高数据库操作的性能和可靠性。
-
监控和调优事务性能:定期对事务性能进行监控和调优。通过分析事务的执行时间和资源消耗情况来发现潜在的性能瓶颈并进行优化处理。
-
处理事务回滚后的异常:在事务回滚后,可能需要处理一些额外的逻辑来恢复系统的状态或通知用户。因此,在编写事务方法时应该考虑到这一点并编写相应的异常处理代码来应对这种情况。
-
避免在事务中调用远程服务:在事务中调用远程服务可能会导致分布式事务的问题,增加系统的复杂性和不确定性。如果必须调用远程服务,可以考虑将远程服务调用放在事务之外或使用其他机制来保证数据的一致性。
-
使用Spring的声明式事务管理:尽可能使用Spring的声明式事务管理来简化事务的配置和管理。通过简单的注解或XML配置就可以实现复杂的事务管理功能,而不需要编写大量的代码来手动管理事务。
总之,Spring事务管理是一个强大而灵活的工具,可以帮助开发者更好地管理数据库事务并提高系统的健壮性和性能。但是,在使用Spring事务管理时也需要注意一些最佳实践和潜在的问题,以确保系统的正确性和可靠性。
相关文章:
Spring 事务和事务传播机制
Spring 事务和事务传播机制 一、Spring 事务的基本概念 事务是一组操作,被视为一个不可分割的工作单元,要么全部完成,要么全部失败回滚,以此来确保数据的一致性和完整性。Spring事务管理允许我们在应用程序中声明式地或编程式地…...
flutter 解决webview加载重定向h5页面 返回重复加载问题
long time no see. 如果觉得该方案helps,点个赞,评论打个call,这是我前进的动力~ 通常写法: 项目里用的webview_flutter 正常webview处理返回事件 if (await controller.canGoBack()) {controller.goBack(); } else {Navigator…...
STM32的寄存器是几位的?
STM32的“32”顾名思义就是32位的意思 但是STM32 的寄存器并不都是 32 位的,它们的位宽取决于具体的寄存器和处理器架构。STM32 是基于 ARM Cortex-M 系列内核的微控制器,而这些内核的寄存器通常有不同的位宽。 具体来说,STM32 微控制器的寄…...
基于python的汽车数据爬取数据分析与可视化
一、研究背景 基于提供的代码片段和讨论,我们可以得出一个与网络抓取、数据处理和数据可视化相关的研究背景,该背景涉及到汽车行业。以下是研究背景的陈述: "在迅速发展的汽车行业中,准确和及时的数据对各方利益相关者至关…...
使用mtools搭建MongoDB复制集和分页集群
mtools介绍 mtools是一套基于Python实现的MongoDB工具集,其包括MongoDB日志分析、报表生成及简易的数据库安装等功能。它由MongoDB原生的工程师单独发起并做开源维护,目前已经有大量的使用者。 mtools所包含的一些常用组件如下: mlaunch支…...
Redis(配置文件属性解析)
一、tcp-backlog深度解析 tcp-backlog是一个TCP连接的队列,主要用于解决高并发场景下客户端慢连接问题。配置文件中的“511”就是队列的长度,对联与TCP的三次握手有关,不同的linux内核,backlog队列中存放的元素(客户端…...
思维导图+实现一个登录窗口界面
QQ2024122-205851 import sys from PyQt6.QtGui import QIcon, QPixmap, QMovie from PyQt6.QtWidgets import QApplication, QWidget, QLineEdit, QPushButton, QLabel, QVBoxLayout# 封装我的窗口类 class LoginWidget(QWidget):# 构造函数def __init__(self):# 初始化父类su…...
T507 buildroot linux4.9之RTC8563开发调试
文章目录 前言一、硬件确认1.1、RTC8563硬件二、驱动配置2.1、驱动位置2.2、使用config宏配置驱动2.3、DTS配置三、断电重启时间不保存分析四、解决问题五、测试前言 调试T507的RTC8563,解决中调试遇到的问题 一、硬件确认 1.1、RTC8563硬件 通过原理图确认 RTC8563 硬件的…...
网络安全专业术语
网络安全专有名词详解 1.肉鸡 被黑客操控的终端设备(电脑、服务器、移动设备等等),黑客可以随心所欲的操作这些终端设备而不会被发觉。 2.木马 表面上伪装成正常的程序,但是当这些程序运行时候就会获取整个系统的控制权限&#…...
【大数据学习 | Spark-SQL】关于RDD、DataFrame、Dataset对象
1. 概念: RDD: 弹性分布式数据集; DataFrame: DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型…...
zerotier实现内网穿透
zerotier的内网穿透 前言一、zerotier的框架认知二、客户端安装设置1.linux2.windows 前言 摸索了一阵,看了好几篇,没有讲清楚。争取这次说清楚。 一、zerotier的框架认知 先认识一下zerotier的框架,这样如何处理就很好理解了。 首先上zero…...
Ardusub源码剖析——control_althold.cpp
代码 #include "Sub.h"/** control_althold.pde - init and run calls for althold, flight mode*/// althold_init - initialise althold controller bool Sub::althold_init() {if(!control_check_barometer()) {return false;}// initialize vertical maximum sp…...
Vue前端开发-路由的基本配置
在传统的 Web 页面开发过程中,可以借助超级链接标签实现站内多个页面间的相互跳转,而在现代的工程化、模块化下开发的Web页面只有一个,在一个页面中需要实现站内各功能页面渲染,相互跳转,这时些功能的实现,…...
HarmonyOS JSON解析与生成 常用的几个方法
HarmonyOS 使用 JSON解析与生成 的好处 一、轻量级与高效性 易于阅读和编写:JSON格式的数据易于人类阅读和编写,降低了数据处理的复杂性。高效解析与生成:HarmonyOS的JSON解析库提供了一系列高效的函数和类,能够快速地将JSON字符串…...
Docker 进阶指南:常用命令、最佳实践与资源管理
Docker 进阶指南:常用命令、最佳实践与资源管理 Docker 作为一种轻量级的容器化技术,已经成为现代软件开发和部署不可或缺的工具。本文将为您深入介绍 Docker 的常用命令、最佳实践以及如何有效管理容器资源,帮助您更好地在 Ubuntu 22.04 或…...
【前端】特殊案例分析深入理解 JavaScript 中的词法作用域
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯案例代码💯词法作用域(Lexical Scope)与静态作用域什么是词法作用域?代码执行的详细分析 💯函数定义与调用的…...
Jmeter进阶篇(29)AI+性能测试领域场景落地
🏝️关于我:我是綦枫。一个顺手写写代码的音乐制作人。 前言 随着2022年GPT3.5的问世,我们的社会已经进入了AI时代,这是一个全新的风口,也会迎来全新的挑战和机遇。如果能抓住新时代的风口,你将会在进步的路上越走越快。今天让我们来一起探究一下,在软件性能测试领域,…...
理解和应用 Python Requests 库中的 .json() 方法:详细解析与示例
理解和应用 Python Requests 库中的 .json() 方法:详细解析与示例 在使用 Python 的 requests 库进行网络请求时,.json() 方法是一种非常实用的功能,用于将从 API 获取的 JSON 格式的字符串响应转换为 Python 可操作的字典或列表。这一功能的…...
docker 运行my-redis命令
CREATE TABLE orders ( order_id bigint NOT NULL COMMENT "订单ID", dt date NOT NULL COMMENT "日期", merchant_id int NOT NULL COMMENT "商家ID", user_id int NOT NULL COMMENT "用户ID", good_id int NOT NULL COMMENT "商…...
cloudstack概要及单节点安装部署
概要 Apache CloudStack 是一个开源的云计算管理平台,用于管理和部署大规模的虚拟化环境,支持 IaaS(基础设施即服务)模型。它广泛应用于私有云、公共云和混合云场景。 核心功能 多租户支持 提供隔离的虚拟网络、计算资源和存储资…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
