Spring声明式事务以及事务传播行为

news2025/1/19 23:05:30

Spring声明式事务以及事务传播行为

  • Spring声明式事务
    • 1.编程式事务
    • 2.使用AOP改造编程式事务
    • 3.Spring声明式事务
  • 事务传播行为

如果对数据库事务不太熟悉,可以阅读上一篇博客简单回顾一下:MySQL事务以及并发访问隔离级别

Spring声明式事务

  1. 事务一般添加到JavaEE三层结构中的service层(业务逻辑层)

  2. 在Spring进行事务管理操作的两种方式

    • 编程式事务管理

    • 声明式事务管理

**转账案例代码准备:**按照以下代码配置完成之后可以进行数据库的操作,但不涉及事务。

image-20240404093723896

  1. 数据库

    create database spring_db;
    use spring_db;
    create table account(
    	id int primary key auto_increment,
    	name varchar(20),
    	money double	
    );
    insert into account values(null,'jack',1000),(null,'rose',1000);
    
  2. 导入Maven依赖

    <dependencies>
        <!--Spring核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <!-- 切入点表达式 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <!--mybatis的包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!--Druid数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <!--数据库驱动包,我的MySQL版本是8.0.33-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!--spring整合mybatis,需要下面两个jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!-- 引入单元测试的jar包(需要在 4.12以上)  -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
        <!-- Spring整合junit的jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
    </dependencies>
    
  3. jdbc.properties配置文件

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/spring_db
    jdbc.username=root
    jdbc.password=123456
    
  4. MyBatisConfig配置类

    public class MyBatisConfig {
        @Bean
        public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource ds){
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            //设置pojo的包扫描
            factoryBean.setTypeAliasesPackage("top.codermao.domain");
            //设置连接池
            factoryBean.setDataSource(ds);
            return factoryBean;
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            //设置dao层的接口扫描
            msc.setBasePackage("top.codermao.dao");
            return msc;
        }
    }
    
  5. Spring配置类

    @Configuration
    @ComponentScan("top.codermao")
    @PropertySource("classpath:jdbc.properties")
    @Import(MyBatisConfig.class)
    public class SpringConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean
        public DataSource getDataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            return ds;
        }
    
    }
    
  6. dao层接口

    public interface AccountDao {
        //转出
        @Update("update account set money = money - #{money} where id = #{outId}")
        int outMoney(@Param("outId") int outId, @Param("money")double money);
        //转入
        @Update("update account set money = money + #{money} where id = #{inId}")
        int inMoney(@Param("inId") int inId, @Param("money")double money);
    }
    
  7. domain包下实体类

    public class Account implements Serializable {
        private Integer id;
        private String name;
        private Double money;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Double getMoney() {
            return money;
        }
    
        public void setMoney(Double money) {
            this.money = money;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", money=" + money +
                    '}';
        }
    
    }
    
  8. service层接口

    public interface AccountService {
        //转账业务
        void transfer(int outId,int inId,double money);
    }
    
  9. service层实现类

    @Service
    public class AccountServiceImpl implements AccountService {
        @Autowired
        private AccountDao dao;
    
        @Override
        public void transfer(int outId, int inId, double money) {
         
            try {
                dao.outMoney(outId, money);
                //可能在转账过程中发生意外: 转出执行,转入还未执行
    //            int i = 1/0;
                dao.inMoney(inId, money);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
      
        }
    }
    
  10. WebApp类充当Controller层,负责数据的发送和接收

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class WebApp {
    
        @Autowired
        private AccountService service;
        @Test
        public void test01(){
            service.transfer(1, 2, 200);
        }
    }
    

1.编程式事务

在学习声明式事务之前我们需要了解编程式事务,因为声明式事务是Spring对编程式事务的封装。

  • 所谓编程式事务是指用Spring中事务相关的API用硬编码方式来实现事务
    • 缺点
      • 事务管理代码和业务代码耦合严重
      • 后续添加其他业务方法还要重新编写事务代码,冗余

所以学习编程式事务,就是学习Spring事务管理相关API。

步骤一:创建事务管理器

# PlatformTransactionManager(平台事务管理器)
1. 这是一个接口,以下是实现类
	1). - DataSourceTransactionManager (重点!!!)
		适用于Spring JDBC或MyBatis
	2). - HibernateTransactionManager 
    	适用于Hibernate3.0及以上版本  
	3). - JpaTransactionManager
		适用于JPA (Java EE 标准之一,为POJO提供持久化标准规范,并规范了持久化开发的统一API,符合JPA规范的开发可以在不同的JPA框架下运行)
2. 	此接口定义了事务的基本操作	
	1). 获取事务 :
      	TransactionStatus getTransaction(TransactionDefinition definition)
	2). 提交事务 :
      	void commit(TransactionStatus status) 
	3). 回滚事务 :
      	void rollback(TransactionStatus status)
	

步骤二:定义事务属性TransactionDefinition

# TransactionDefinition(定义事务属性)
1. 实现类
		DefaultTransactionDefinition
2. 此接口定义了事务的基本信息
//2. 创建事务定义对象
DefaultTransactionDefinition td = new DefaultTransactionDefinition();
/*
    设置事务隔离级别
        0). spring默认隔离级别是跟数据库软件一致
        1). mysql默认是REPEATABLE_READ
        2). oracle默认是READ_COMMITTED
 */
td.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
/*
    设置是否只读
     1). false,表示读写均可(默认设置,适合增删改操作)
     2). true,表示只读(适合查,效率高)
*/
td.setReadOnly(false);
/*
  	设置超时时间
         1). 默认值是-1, 表示永不超时
         2). 单位是秒
*/
td.setTimeout(10);
/*
    设置事务传播行为
        1. 一般增删改:REQUIRED (默认值)
        2. 一般查询  SUPPORTS
*/
td.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

步骤三:开启事务

# TransactionStatus(接口)
`public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException`
调用事务管理器的getTransaction方法,即可开启一个事务
这个方法会返回一个TransactionStatus表示事务状态的一个对象,通过TransactionStatus提供的一些方法可以用来控制事务的一些状态,比如事务最终是需要回滚还是需要提交。

- 获取事务是否处于新开启事务状态
	- boolean isNewTransaction()
- 获取事务是否处于已完成状态
	- boolean isCompleted()
- 获取事务是否处于回滚状态
	- boolean isRollbackOnly()
- 刷新事务状态
	- void flush()
- 获取事务是否具有回滚存储点
	- boolean hasSavepoint()
- 设置事务处于回滚状态
	- void setRollbackOnly()

步骤四:执行业务操作

  • 书写业务逻辑代码

步骤五:提交 or 回滚

  • 无异常发生,提交

    dstm.commit(ts);
    
  • 有异常发生,回滚

    dstm.rollback(ts);
    

对service层AccountServiceImpl的transfer方法添加编程式事务

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao dao;

    @Autowired
    private DataSource dataSource;

    @Override
    public void transfer(int outId, int inId, double money) {

        //1.创建事务管理器
        DataSourceTransactionManager dstm = new DataSourceTransactionManager();
        //为事务管理器添加与数据层相同的数据源
        dstm.setDataSource(dataSource);
        //2.创建事务定义对象,设置隔离级别、传播特性、超时时间...
        DefaultTransactionDefinition td = new DefaultTransactionDefinition();
        /*
            设置事务隔离级别
                0). spring默认隔离级别是跟数据库软件一致 (ISOLATION_DEFAULT)
                1). mysql默认是REPEATABLE_READ
                2). oracle默认是READ_COMMITTED
         */
        td.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
        /*
           设置是否为只读事务
               1). false,表示读写均可(默认设置,适合增删改操作)
               2). true,表示只读(适合查,效率高)
         */
        td.setReadOnly(false);
        /*
            设置超时时间
               1). 默认值是-1, 表示永不超时
               2). 单位是秒
         */
        td.setTimeout(10);
        /*
            设置事务传播行为
                1. 一般增删改:REQUIRED (默认值)
                2. 一般查询  SUPPORTS
        */
        td.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //3.创建事务状态对象,用于控制事务执行(了解)  -> 相当于开启事务
        TransactionStatus ts = dstm.getTransaction(td);
        try {
            dao.outMoney(outId, money);
            //可能在转账过程中发生意外: 转出执行,转入还未执行
//            int i = 10/0;
            dao.inMoney(inId, money);
            dstm.commit(ts);//成功,提交
        } catch (Exception e) {
            e.printStackTrace();
            dstm.rollback(ts);//失败,回滚
        }
    }
}

2.使用AOP改造编程式事务

硬编码方式添加事务耦合度比较高,AOP面向切面编程是动态增强方法,如果引入AOP则可以将业务代码和事务代码分开,实现解耦。

使用AOP处理编程式事务解决了耦合问题。。但是还是有些不够完美。。AOP处理不具备特例性,任何业务添加事务都是一样的操作,对某些事务可能对事务属性有一些独特的设置。

步骤一:在SpringConfig上添加开启AOP的注解

...
@EnableAspectJAutoProxy
public class SpringConfig {
    ...
}

步骤二:AccountServiceImpl中transfer中只需要书写业务代码

  • 注意:注意: 在aop使用中,切入点方法transfer千万不能自己catch异常
@Service
public class AccountServiceImpl implements AccountService {
    /*
    注意: 在aop使用中,切入点方法千万不能自己catch异常
    原因: 如果切入点自己catch了异常,那么通知中是调用切入点的地方是不会感知到异常,就不会执行catch了
         (相当于异常通知失效)
    解决方案:
        A方案: 有异常直接抛出,不要catch
        B方案: 可以catch,但是再new一个异常抛出
 	*/
    @Override
	public void transfer(int outId, int inId, double money) {
        dao.outMoney(outId, money);
        //可能在转账过程中发生意外: 转出执行,转入还未执行
        //int i = 1/0;
        dao.inMoney(inId, money);
	}
}

步骤三:添加TxAdvice

  • 将编程式事务中对事务操作的代码抽取到TxAdvice切面类中
package top.codermao.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;

@Component
@Aspect
public class TxAdvice {
    @Autowired
    private DataSource dataSource;

    @Pointcut("execution(* top.codermao.service.*Service.transfer(..))")
    public void pt(){}

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp){
        Object result = null;
        //1. 创建事务管理器
        DataSourceTransactionManager dstm = new DataSourceTransactionManager();
        //为事务管理器设置与数据层相同的数据源!!!
        dstm.setDataSource(dataSource);
        //2. 创建事务定义对象 : 隔离级别/传播特性/超时时间...
        DefaultTransactionDefinition td = new DefaultTransactionDefinition();
        td.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        td.setReadOnly(false);
        td.setTimeout(10);
        td.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //3.创建事务状态对象,用于控制事务执行(了解)  -> 相当于开启事务
        TransactionStatus ts = dstm.getTransaction(td);
        try{
            result = pjp.proceed();
            dstm.commit(ts);//成功,提交
        } catch (Throwable e) {
            e.printStackTrace();
            dstm.rollback(ts);//失败,回滚
            System.out.println("aop改造编程式事务");
        }
        return  result;
    }
}

3.Spring声明式事务

spring底层封装了事务切面类TxAdvice, 让开发者声明配置即可用

步骤一:在SpringConfig类上添加注解开启Spring事务管理支持

...
@EnableTransactionManagement
public class SpringConfig {
    ...
}

步骤二:在SpringConfig类中配置事务管理器

...
@EnableTransactionManagement
public class SpringConfig {
    ...
        
    @Bean
    public DataSourceTransactionManager getTxManager(DataSource dataSource){
        //这里使用DataSourceTransactionManager,因为使用的是MyBatis
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(dataSource);
        return manager;
    }
}

步骤三:在需要添加事务的方法上添加@Transactional注解使其成为切入点

  • @Transactional注解属性

    • 属性都有默认值

    image-20240404110247388

  • @Transactional放置位置不同,效果不同

    • 如果放在类的方法上,说明当前方法是切入点
    • 如果放在类上,说明当前类的所有方法是切入点
    • 如果放在接口的方法上,说明此方法的所有重写方法是切入点 (常用)
    • 如果放在接口上,说明此接口的所有实现类的所有方法都是切入点 (常用)

事务传播行为

事务传播行为:指的就是当一个事务方法B被另一个事务方法A调用时,这个事务方法B应该对待A的事务态度。(B是自己开启一个新事务,还是融入A的事务,或者不添加事务,或者…)

Spring事务角色 事务管理员 + 事务协调员

  • 事务管理员一般是业务层,事务A

  • 事务协调员一般是数据层,事务B

再次翻译下事务传播行为:事务传播行为是指事务协调员对于事务管理员的态度@Transactional中的propagation属性

下图来源于:B站视频,点击进入,,我觉得讲的很好,,建议大家去瞅瞅。。

image-20240404111405347

案例:往面转账案例添加一个记录日志的功能,要求转账成功之后,要给account_log表插入谁向谁转了多少钱

  1. 添加一个数据表

    create table account_log(
        out_id int,
        in_id int,
        money double
    );
    
  2. dao层接口添加方法

    public interface AccountDao {
        //转出
        @Update("update account set money = money - #{money} where id = #{outId}")
        int outMoney(@Param("outId") int outId, @Param("money")double money);
        //转入
        @Update("update account set money = money + #{money} where id = #{inId}")
        int inMoney(@Param("inId") int inId, @Param("money")double money);
    	//记录日志
        @Insert("insert into account_log values(#{outId},#{inId},#{money})")
        void insertLog(@Param("outId") int outId, @Param("inId") int inId,@Param("money") double money);
    }
    
  3. service层的AccountServiceImpl修改为

    @Service
    public class AccountServiceImpl02 implements AccountService {
        @Autowired
        private AccountDao dao;
    
        @Autowired
        private DataSource dataSource;
    
        /**
        	转账事务
        */
        @Transactional(
                propagation = Propagation.REQUIRED
        )
        public void s1(int outId,int inId,double money){
            dao.outMoney(outId,money);
            //可能在转账过程中发生意外: 转出执行,转入还未执行
            dao.inMoney(inId,money);
        }
    
        /**
        	记录日志事务
        */
        @Transactional(
                propagation = Propagation.REQUIRES_NEW
        )
        public void s2(int outId,int inId,double money){
            dao.insertLog(outId,inId,money);
        }
    
        /**
            业务逻辑:
            1). 如果转账S1操作失败了, S1需要回滚(S1的操作肯定需要事务)
                如果S1有事务,S1跟随即可, 如果S1没有事务,S1需要自己创建事务
                所以S1适合设置传播行为属性为REQUIRED
            2). 如果S1成功,S2向数据库中插入日志
            	如果转账S1操作失败了, S2不需要回滚,也向数据库中插入日志
            	所以S2适合设置传播行为属性为REQUIRES_NEW			
        */
        @Transactional
        @Override
        public void transfer(int outId, int inId, double money) {
            s1(outId,inId,money);
    //            int i = 10 / 0;
            s2(outId,inId,money);
        }
    }
    

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

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

相关文章

安装Docker(CentOS)

Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道。 官方网站上…

212 基于matlab的双稳态随机共振的算法

基于matlab的双稳态随机共振的算法&#xff0c;分析信噪比随系统参数a,b及乘性噪声和加性噪声的增益变化曲线&#xff0c;60个数据样本可供选择。程序已调通&#xff0c;可直接运行。 212 双稳态随机共振 信噪比增益变化曲线 - 小红书 (xiaohongshu.com)

【SQL Server的详细使用教程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【.NET全栈】.NET全栈学习路线

一、微软官方C#学习 https://learn.microsoft.com/zh-cn/dotnet/csharp/tour-of-csharp/ C#中的数据类型 二、2021 ASP.NET Core 开发者路线图 GitHub地址&#xff1a;https://github.com/MoienTajik/AspNetCore-Developer-Roadmap/blob/master/ReadMe.zh-Hans.md 三、路线…

书生浦语训练营2期-第二节课笔记作业

目录 一、前置准备 1.1 电脑操作系统&#xff1a;windows 11 1.2 前置服务安装&#xff08;避免访问127.0.0.1被拒绝&#xff09; 1.2.1 iis安装并重启 1.2.2 openssh安装 1.2.3 openssh服务更改为自动模式 1.2.4 书生浦语平台 ssh配置 1.3 补充&#xff08;前置服务ok…

电池二次利用走向可持续大循环周期的潜力和挑战(第一篇)

一、背景 当前&#xff0c;气候变化是全球可持续发展面临的重大挑战。缓解气候变化最具挑战性的目标是在本世纪中期实现碳中和&#xff08;排放量低到足以被自然系统安全吸收&#xff09;&#xff0c;其中电动汽车&#xff08;EV&#xff09;的引入是一项关键举措。电动汽车在…

小林coding图解计算机网络|基础篇01|TCP/IP网络模型有哪几层?

小林coding网站通道&#xff1a;入口 本篇文章摘抄应付面试的重点内容&#xff0c;详细内容还请移步&#xff1a; 文章目录 应用层(Application Layer)传输层(Transport Layer)TCP段(TCP Segment) 网络层(Internet Layer)IP协议的寻址能力IP协议的路由能力 数据链路层(Link Lay…

每日一题:用c语言中指针实现除2操作

目录 一、要求 二、实现代码 三、实现结果 四、关于指针的相关知识 一、要求 二、实现代码 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void change(int *i) {*i*i/2; }int main() {int i;printf("请您输入一个整数&#xff1a;");scanf(&quo…

LC 111.二叉树的最小深度

111. 二叉树的最小深度 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a; 叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a; root [3,9,20,null,null,15,7] 输出&#xff1a;…

LeetCode-124. 二叉树中的最大路径和【树 深度优先搜索 动态规划 二叉树】

LeetCode-124. 二叉树中的最大路径和【树 深度优先搜索 动态规划 二叉树】 题目描述&#xff1a;解题思路一&#xff1a;递归。return max(max(l_val, r_val) node.val, 0)解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 二叉树中的 路径 被定义为一条…

景联文科技提供高质量医疗健康AI大模型数据

医疗行业是典型的知识和技术密集型行业&#xff0c;其发展水平直接关系到国民健康和生命质量。 医疗健康AI大模型&#xff0c;作为人工智能的一个分支&#xff0c;能够通过学习大量的数据来生成新的数据实例&#xff0c;在医药研发、医学影像、医疗文本分析等都有广泛的应用前景…

基于单片机的无线红外报警系统

**单片机设计介绍&#xff0c;基于单片机的无线红外报警系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的无线红外报警系统是一种结合了单片机控制技术和无线红外传感技术的安防系统。该系统通过无线红外传感器实…

满足小体积/低功耗/低成本需求,世强硬创推出CGM解决方案

随着CGM的普及与更多具备性价比的国产产品上市&#xff0c;越来越多的企业开始布局CGM市场。 为此全球领先的硬件创新研发和供应服务平台世强硬创面向硬科技企业推出CGM&#xff08;连续血糖监测&#xff09;解决方案。 该方案可一站式解决企业开发需求&#xff0c;包括系统整…

vivado 系统监控器

系统监控器 (SYSMON) 模数转换器 (ADC) 用于测量硬件器件上的裸片温度和电压。 SYSMON 可通过片上温度和供电传 感器来监控物理环境。 ADC 可为各种应用提供高精度模拟接口。 请参阅下文 &#xff0c; 以获取有关特定器件架构的更多信息 &#xff1a; • 《 UltraScale …

前视声呐目标识别定位(五)-代码解析之修改声呐参数

前视声呐目标识别定位&#xff08;一&#xff09;-基础知识 前视声呐目标识别定位&#xff08;二&#xff09;-目标识别定位模块 前视声呐目标识别定位&#xff08;三&#xff09;-部署至机器人 前视声呐目标识别定位&#xff08;四&#xff09;-代码解析之启动识别模块 …

售价 25.98 万元起,远航 Y6、H8 焕新来袭,让高端豪华电动汽车真正“触手可及”

当下的新能源汽车市场中&#xff0c;各品牌竞争激烈&#xff0c;远航汽车通过一系列专属的权益优惠&#xff0c;以令人惊喜的25.98 万元起售价&#xff0c;远航 Y6 、H8成功打破高端豪华电动汽车价格壁垒&#xff0c;相比同类产品更具竞争力&#xff0c;为广大消费者带来了更轻…

7.stack容器的使用

文章目录 stack容器常用接口代码工程运行结果 stack容器 常用接口 /*1.push - 入栈*/ /*2.top - 查看栈顶元素*/ /*3.pop - 出栈*/代码工程 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<stack>using namespace std;/*1.push - 入栈*/ /*2.top…

开机自启动

对win10,给一种开机自启动的设置方法: 1. winr 打开 2. 输入shell:startup打开 开始\程序\启动 3. 把想要自启动的应用的快捷方式放在这里即可 亲测有用

2024年腾讯云4核8G12M轻量服务器并发量评测,能支持多少人?

腾讯云4核8G服务器价格&#xff1a;轻量4核8G12M优惠价格646元15个月、CVM S5服务器4核8G配置1437元买1年送3个月。腾讯云4核8G服务器支持多少人同时在线&#xff1f;支持30个并发数&#xff0c;可容纳日均1万IP人数访问。腾讯云百科txybk.com整理4核8G服务器支持多少人同时在线…

B02、运行时内存篇-3.2

1、堆 1.1、核心概述 一个JVM实例只存在一个堆内存&#xff0c;堆也是Java内存管理的核心区域。Java 堆区在JVM启动的时候即被创建&#xff0c;其空间大小也就确定了。是JVM管理的最大一块内存空间。 堆内存的大小是可以调节的。在《Java虚拟机规范》规定&#xff0c;堆可以处…