Spring《声明式事务》

知识点: Spring 声明式事务

1.基于注解和配置类的Spring-jdbc环境搭建

 1. 准备项目,pom.xml

<dependencies>
    <!--spring context依赖-->
    <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.6</version>
    </dependency>
    <!--注解-->
    <dependency>
        <groupId>jakarta.annotation</groupId>
        <artifactId>jakarta.annotation-api</artifactId>
        <version>2.1.1</version>
    </dependency>
    <!-- 数据库驱动 和 连接池-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.8</version>
    </dependency>
    <!-- spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.0.6</version>
    </dependency>
    <!--日志-->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.26</version>
    </dependency>
    <!--junit5测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.3.1</version>
    </dependency>

<!--test测试-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>6.0.6</version>
        <scope>test</scope>
    </dependency>
</dependencies>

注意:引入logback.xml的日志文件

2. 外部配置文件 jdbc.properties

jdbc.url=jdbc:mysql://localhost:3306/studb?serverTimezone=UTC
jdbc.userName=root
jdbc.userPwd=
jdbc.driverClass=com.mysql.cj.jdbc.Driver

3.Spring 配置类

@Configuration
@ComponentScan("com.bdqn")
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
    //@Value 通常用于注入外部化属性
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driverClass}")
    private String driver;
    @Value("${jdbc.userName}")
    private String username;
    @Value("${jdbc.userPwd}")
    private String password;

    /**
     * 创建数据源对象:druid连接池
     * @Bean 注释用于指示方法实例化、配置和初始化要由 Spring IoC 容器管理的新对象。
     * 对于那些熟悉 Spring <beans/> XML 配置的人来说, @Bean 注释与 <bean/> 元素起着相同的作用。
     */
    @Bean
    public DataSource  dataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * jdbcTemplate:jdbc模版对象
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
}

4.准备实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private int id;
    private String name;
    private String gender;
    private int age;
    private String classes;
}

5.准备dao层

1.dao接口

public interface StudentDao {
    int updateNameById(int id,String name);
    int updateAgeById(int id,int age);
}

 2.dao实现类

@Repository
public class StudentDaoImpl implements StudentDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int updateNameById(int id,String name){
        String sql = "update student set name = ? where id = ? ";
        int row= jdbcTemplate.update(sql, name, id);
        return row;
    }

    public int updateAgeById(int id,int age){
        String sql = "update student set age = ? where id = ? ";
        int row=jdbcTemplate.update(sql,age,id);
        return row;
    }
}

6.准备service层

6.2service接口,提供修改用户信息的方法

public interface StudentService {
    void  changeInfo();
}

6.2service实现类

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentDao studentDao;

    /**
     * 修改学生信息的业务方法
     */
    public void changeInfo(){
        studentDao.updateAgeById(1,28);
        System.out.println("-----------");
        studentDao.updateNameById(1,"张小三");
    }
}

7.测试环境搭建

package com.bdqn.test;

@SpringJUnitConfig(SpringConfig.class)
public class TestTx {
    @Autowired
    private StudentService studentService;

    @Test
    public void  test01(){
        studentService.changeInfo();
    }
}

  注意:修改学生信息的业务,需要执行2条DML的SQL语句。如果不采用事务控制,可能会导致一条sql成功,一条sql失败。导致出现数据的不合理。

2.编程式事务

  编程式事务是指手动编写程序来管理事务,即通过编写代码的方式直接控制事务的提交和回滚。在 Java 中,通常使用事务管理器(如 Spring 中的 PlatformTransactionManager)来实现编程式事务。

  编程式事务的主要优点是灵活性高,可以按照自己的需求来控制事务的粒度、模式等等。但是,编写大量的事务控制代码容易出现问题,对代码的可读性和可维护性有一定影响。

Connection conn = ... ;

try {

    // 开启事务:关闭事务的自动提交

    conn.setAutoCommit(false);

    // 核心操作

    // 业务代码

    // 提交事务

    conn.commit();

  

}catch(Exception e){

  

    // 回滚事务

    conn.rollBack();

  

}finally{

  

    // 释放数据库连接

    conn.close();

  

}

   编程式的实现方式存在缺陷:

    - 细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐。

- 代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,代码就没有得到复用。

3.声明式事务

声明式事务是指使用注解或 XML 配置的方式来控制事务的提交和回滚。

开发者只需要添加配置即可,具体事务的实现由第三方框架实现,避免我们直接进行事务操作!

使用声明式事务可以将事务的控制和业务逻辑分离开来,提高代码的可读性和可维护性。

区别:

- 编程式事务需要手动编写代码来管理事务

- 而声明式事务可以通过配置文件或注解来控制事务。

4.Spring事务管理器

   1.Spring声明式事务对应依赖

  spring-tx: 包含声明式事务实现的基本规范(事务管理器规范接口和事务增强等等)

   spring-jdbc: 包含DataSource方式事务管理器实现类DataSourceTransactionManager
       spring-orm: 包含其他持久层框架的事务管理器实现类例如:Hibernate/Jpa等

   2.Spring声明式事务对应事务管理器接口

我们现在要使用的事务管理器是org.springframework.jdbc.datasource.DataSourceTransactionManager,将来整合 JDBC方式、JdbcTemplate方式、Mybatis方式的事务实现!

DataSourceTransactionManager类中的主要方法:

  doBegin():开启事务

  doSuspend():挂起事务

  doResume():恢复挂起的事务

  doCommit():提交事务

  doRollback():回滚事务

5.基于事务控制实现

1.引入声明式事务相关的依赖

<!-- 声明式事务依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>6.0.6</version>
    </dependency>
    <!--aop依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>6.0.6</version>
    </dependency>

2.配置事务管理器 ,配置数据库相关的配置类

@Configuration
@ComponentScan("com.bdqn")
@PropertySource("classpath:jdbc.properties")

//开启事务管理器
@EnableTransactionManagement
public class DataSourceConfig{
    //@Value 通常用于注入外部化属性
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driverClass}")
    private String driver;
    @Value("${jdbc.userName}")
    private String username;
    @Value("${jdbc.userPwd}")
    private String password;

    /**
     * 实例化dataSource加入到ioc容器.创建数据源对象:druid连接池
     */
    @Bean
    public DataSource  dataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * jdbcTemplate:jdbc模版对象
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    /**
     * 装配事务管理实现对象
     */
    @Bean
    public TransactionManager transactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

3. 使用声明事务注解@Transactional进行事务控制

@Service
public class StudentService {

    @Autowired
    private StudentDao studentDao;

    //使用声明式事务
    @Transactional
    public void changeInfo(){
        studentDao.updateAgeById(2,18);
        System.out.println("-----------");
        studentDao.updateNameById(2,"李小四");
    }
}

4. 测试事务效果

@SpringJUnitConfig(DataSourceConfig.class)
public class TestTx {
    @Autowired
    private StudentService studentService;

    @Test
    public void  testTx(){
        studentService.changeInfo();
    }
}

6.事务属性:只读

   1.只读介绍

     对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。

   2.设置方式

//readOnly = true把当前事务设置为只读 默认是false!
@Transactional(readOnly = true)

   3.针对DML动作设置只读模式

会抛出下面异常:Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

   4. @Transactional注解放在类上  

   1. 生效原则

   如果一个类中每一个方法上都使用了 @Transactional 注解,那么就可以将 @Transactional 注解提取到类上。反过来说:@Transactional 注解在类级别标记,会影响到类中的每一个方法。同时,类级别标记的 @Transactional 注解中设置的事务属性也会延续影响到方法执行时的事务属性。除非在方法上又设置了 @Transactional 注解。

  对一个方法来说,离它最近的 @Transactional 注解中的事务属性设置生效。

   2. 用法举例

   在类级别@Transactional注解中设置只读,这样类中所有的查询方法都不需要设置@Transactional注解了。因为对查询操作来说,其他属性通常不需要设置,所以使用公共设置即可。

  然后在这个基础上,对增删改方法设置@Transactional注解 readOnly 属性为 false。

@Service
@Transactional(readOnly = true)
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentDao studentDao;

    /**
     * 修改用户信息的业务方法,需要加入事务的控制
     */
    @Transactional(readOnly = false)
    public void changeInfo(){
        studentDao.updateAgeById(2,18);
        System.out.println("-----------");
        studentDao.updateNameById(2,"李小四");

    }

    /**
     * 获取学生信息
     * readOnly = true把当前事务设置为只读 默认是false!
     */
    @Transactional(readOnly = true)
    public Student getStudent(int id){
        Student stu=studentDao.selectById(id);
        return stu;
    }
}

7.事务属性:超时时间

   1.需求

    事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。

    此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。

    概括来说就是一句话:超时回滚,释放资源。

   2.设置超时时间

@Service
public class StudentService {
    @Autowired
    private StudentDao studentDao;

    /**
     * 使用声明式事务
     * timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
     */
    @Transactional(readOnly = false,timeout = 3)
    public void changeInfo(){
        studentDao.updateAgeById(3,15);
        //休眠4,等待方法超时!
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("-----------");
        studentDao.updateNameById(3,"");
    }
}

   3.测试超时效果 :执行抛出事务超时异常

8.事务属性:事务异常

   1. 默认情况

      默认只针对运行时异常回滚,编译时异常不回滚。情景模拟代码如下:

@Service
public class StudentService {
    @Autowired
    private StudentDao studentDao;
    /**
     * 使用声明式事务
     * timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
     * 默认只针对运行时异常回滚,编译时异常不回滚
     * rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
     * noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
     */
    @Transactional(readOnly = false,timeout = 3)
    public void changeInfo() throws FileNotFoundException {
        studentDao.updateAgeById(6,56);
        //主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内!
        new FileInputStream("xxxx");
        System.out.println("-----------");
        studentDao.updateNameById(6,"赵小六");
    }
}

   2.设置回滚异常

     rollbackFor属性:指定哪些异常类才会回滚,默认是 RuntimeException and Error 异常方可回滚!

     /**
     * 使用声明式事务
     * timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
     * 默认只针对运行时异常回滚,编译时异常不回滚
     * rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
     * noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
     */
    @Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class)
    public void changeInfo() throws FileNotFoundException {
        studentDao.updateAgeById(6,56);
        //主动抛出一个检查异常,测试! 发现会回滚,因为在rollbackFor的指定范围内!
        new FileInputStream("xxxx");
        System.out.println("-----------");
        studentDao.updateNameById(6,"赵小六");
    }

   3.设置不回滚的异常

    在默认设置和已有设置的基础上,再指定一个异常类型,碰到它不回滚。

noRollbackFor属性:指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!

/**
 * 使用声明式事务
 * timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
 * 默认只针对运行时异常回滚,编译时异常不回滚
 * rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
 * noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
 */
@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class)
public void changeInfo() throws FileNotFoundException {
    studentDao.updateAgeById(6,78);
    //主动抛出一个检查异常,测试! 发现不会回滚,因为在noRollbackFor指定范围内!
    new FileInputStream("xxxx");
    System.out.println("-----------");
    studentDao.updateNameById(6,"赵小六");

}

9.事务属性:事务隔离级别

   1.事务隔离级别

数据库事务的隔离级别是指在多个事务并发执行时,数据库系统为了保证数据一致性所遵循的规定。常见的隔离级别包括:

1. 读未提交(Read Uncommitted):事务可以读取未被提交的数据,容易产生脏读、不可重复读和幻读等问题。实现简单但不太安全,一般不用。

2. 读已提交(Read Committed):事务只能读取已经提交的数据,可以避免脏读问题,但可能引发不可重复读和幻读。

3. 可重复读(Repeatable Read):在一个事务中,相同的查询将返回相同的结果集,不管其他事务对数据做了什么修改。可以避免脏读和不可重复读,但仍有幻读的问题。

4. 串行化(Serializable):最高的隔离级别,完全禁止了并发,只允许一个事务执行完毕之后才能执行另一个事务。可以避免以上所有问题,但效率较低,不适用于高并发场景。

不同的隔离级别适用于不同的场景,需要根据实际业务需求进行选择和调整。

   2.事务隔离级别设置

/**
 * 使用声明式事务
 * timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
 * 默认只针对运行时异常回滚,编译时异常不回滚
 * rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
 * noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
 * isolation = 设置事务的隔离级别,mysql默认是repeatable read!
 */
@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class,
        noRollbackFor = FileNotFoundException.class,

        isolation = Isolation.REPEATABLE_READ)
public void changeInfo() throws FileNotFoundException {
    studentDao.updateAgeById(6,78);
    new FileInputStream("xxxx");
    System.out.println("-----------");
    studentDao.updateNameById(6,"赵小六");
}

10.事务属性:事务传播行为

  1.事务传播行为要研究的问题

2.举例代码

@Transactional

public void MethodA(){

    // ...

    MethodB();

    // ...

}

//在被调用的子方法中设置传播行为,代表如何处理调用的事务! 是加入,还是新事务等!

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void MethodB(){

    // ...

}

   3.propagation属性

      @Transactional 注解通过 propagation 属性设置事务的传播行为。它的默认值是:

 Propagation propagation() default Propagation.REQUIRED;

         propagation 属性的可选值由 Propagation 枚举类提供:

1. Propagation.REQUIRED:如果当前存在事务,则加入当前事务,否则创建一个新事务。

2. Propagation.REQUIRES_NEW:创建一个新事务,并在新事务中执行。如果当前存在事务,则挂起当前事务,即使新事务抛出异常,也不会影响当前事务。

3. Propagation.NESTED:如果当前存在事务,则在该事务中嵌套一个新事务,如果没有事务,则与Propagation.REQUIRED一样。

4. Propagation.SUPPORTS:如果当前存在事务,则加入该事务,否则以非事务方式执行。

5. Propagation.NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,挂起该事务。

6. Propagation.MANDATORY:必须在一个已有的事务中执行,否则抛出异常。

7. Propagation.NEVER:必须在没有事务的情况下执行,否则抛出异常。

 4. 测试

      1.声明两个业务方法

@Service

public class StudentService {

    @Autowired

private StudentDao studentDao;    

    /**

     * 声明两个独立修改数据库的事务业务方法

     */

    @Transactional(propagation = Propagation.REQUIRED)

    public void changeAge(){

        studentDao.updateAgeById(1,99);

    }

    @Transactional(propagation = Propagation.REQUIRED)

    public void changeName(){

        studentDao.updateNameById(1,"小张");

        int i = 1/0;

    }

}

2. 声明一个整合业务方法

@Service

public class TopService {

    @Autowired

    private StudentService studentService;

    @Transactional

    public void  topService(){

        studentService.changeAge();

        studentService.changeName();

    }

}

3.添加传播行为测试

@SpringJUnitConfig(classes = AppConfig.class)

public class TxTest {

    @Autowired

    private TopService topService;

    @Test

    public void  testTx() throws FileNotFoundException {

        topService.topService();

    }

}

**注意:**

  在同一个类中,对于@Transactional注解的方法调用,事务传播行为不会生效。这是因为Spring框架中使用代理模式实现了事务机制,在同一个类中的方法调用并不经过代理,而是通过对象的方法调用,因此@Transactional注解的设置不会被代理捕获,也就不会产生任何事务传播行为的效果。

   

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

七款主流图纸加密软件强力推荐|2024年CAD图纸加密保护指南

在当今信息化的设计行业&#xff0c;保护CAD图纸的知识产权和数据安全变得尤为重要。随着越来越多的企业采用数字化设计和共享文件&#xff0c;如何防止CAD图纸被未经授权的访问和窃取成为了许多设计师和企业关注的焦点。为此&#xff0c;选用合适的图纸加密软件是保护CAD文件安…

《数据结构》学习系列——树(下)

系列文章目录 目录 树和森林的遍历树的遍历森林的遍历基本算法递归先根遍历树迭代先根遍历树树和森林的层次遍历 压缩与哈夫曼树文件编码扩充二叉树哈夫曼树和哈夫曼编码哈夫曼树的基本思路哈夫曼编码 树和森林的遍历 树的遍历 先根遍历&#xff1a;先访问树的根结点&#x…

想作弊❓用这个发起考试,根本没法作弊

&#x1f389; 推荐一款超实用的在线考试神器 —— 土著刷题✨ 如果你正在寻找一个既方便又高效的在线考试平台&#xff0c;那么“土著刷题”小&#x1f34a;序绝对值得一试&#xff01;它不仅完全免费&#xff0c;而且操作简单&#xff0c;非常适合用来组织线上测试。 &#x…

使用Angular构建动态Web应用

&#x1f496; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4bb; Gitee主页&#xff1a;瑕疵的gitee主页 &#x1f680; 文章专栏&#xff1a;《热点资讯》 使用Angular构建动态Web应用 1 引言 2 Angular简介 3 安装Angular 4 创建Angular项目 5 设计应用结构 6 创建组件 7 …

「Java SPI机制应用快速入门」: 一种JDK内置的服务提供发现机制

文章目录 什么是SPISPI机制的应用使用方法使用规范 入门案例 什么是SPI SPI首先是一种机制&#xff0c;这个机制叫&#xff1a;服务提供发现机制。那是谁来负责发现呢&#xff1f;当然是JDK内置的服务帮助我们发现啦。发现了帮助我们去调用&#xff0c;我们要做的就是在中间去…

2024护理类科技核心期刊汇总(最新版)

2024年9月中国科技核心期刊目录&#xff08;2024年版&#xff09;正式公布&#xff0c;13本护理类期刊入选。常笑医学整理了这13本护理类科技核心期刊的详细参数&#xff0c;以及投稿经验&#xff0c;供大家在论文投稿时参考&#xff0c;有需要的赶紧收藏&#xff01; 1.《中华…

SwiftUI(四)- 布局(VStack、HStack、ZStack)

引言 页面的搭建和布局在应用开发中几乎占据了一半的代码量。定于iOS开发而言&#xff0c;相较于其它平台&#xff0c;UIKit的布局方式显得相对局限&#xff0c;通常只有绝对布局和相对布局两种方案。而在Flutter或者Android开发中&#xff0c;布局选项更为丰富&#xff0c;比…

【mod分享】极品飞车9冬日mod,支持光追,想体验一把冬天的Rockport市吗

各位好&#xff0c;今天小编给大家带来一款新的高清重置魔改MOD&#xff0c;本次高清重置的游戏叫《极品飞车9最高通缉》。 《极品飞车&#xff1a;最高通缉》作为一款2005年的游戏&#xff0c;《极品飞车&#xff1a;最高通缉》的画面效果还是可以的&#xff0c;效果全开之后…

【状态机DP】力扣1186. 删除一次得到子数组最大和

给你一个整数数组&#xff0c;返回它的某个 非空 子数组&#xff08;连续元素&#xff09;在执行一次可选的删除操作后&#xff0c;所能得到的最大元素总和。换句话说&#xff0c;你可以从原数组中选出一个子数组&#xff0c;并可以决定要不要从中删除一个元素&#xff08;只能…

手机拍证件照,换正装有领衣服及底色的方法

证件照在我们的职业生涯的关键节点是经常会用到的&#xff0c;比如毕业入职、人事档案建立、升迁履历、执业资格考试和领证等&#xff0c;这些重要的证件照往往要求使用正装照&#xff0c;有时候手头没有合适的衣服&#xff0c;或者原先的证件照背景色不符合要求&#xff0c;就…

numpy——数学运算

一、标量——矢量 import numpy as npa 3.14 b np.array([[9, 5], [2, 7]])print(a) print(b)# ---------- 四则运算 ---------- print(a b) # np.add print(a - b) # np.subtract print(a * b) # np.multiply print(a / b) # np.divide 二、矢量——矢量 import nump…

优选算法精品课--双指针算法(2)

双指针算法&#xff08;2&#xff09; 1、有效三角形的个数1.1 题目解析1.2 思路解析1.3 代码实现 2、和为s的两个数2.1 题目解析2.2 思路解析2.3 代码实现 3、三数之和3.1 题目解析3.2 思路解析3.3 代码实现 4、四数之和4.1 题目解析4.2 思路解析4.3 代码实现 5 总结 1、有效三…

4个提取音频办法,轻松实现视频转音频!

在信息爆炸的时代&#xff0c;视频内容以其直观、生动的特点占据了互联网的大半江山。然而&#xff0c;在某些场景下&#xff0c;我们可能更倾向于只听取音频部分&#xff0c;无论是驾驶途中听讲座、跑步时享受音乐视频中的纯音乐的场景&#xff0c;还是为了节省流量和存储空间…

Python continue和break

continue的作用是&#xff1a; 中断所在循环的当次执行&#xff0c;直接进入下一次 break的作用是&#xff1a; 直接结束所在的循环 注意事项&#xff1a; continue和break&#xff0c;在for和while循环中作用一致 在嵌套循环中&#xff0c;只能作用在所在的循环上&#x…

【01初识】-初识 RabbitMQ

目录 学习背景1- 初识 MQ1-1 同步调用什么是同步调用&#xff1f;小结&#xff1a;同步调用优缺点 1-2 异步调用什么是异步调用&#xff1f;小结&#xff1a;异步调用的优缺点&#xff0c;什么时候使用异步调用&#xff1f; 1-3 MQ 技术选型 学习背景 异步通讯的特点&#xff…

300元蓝牙耳机性价比高的有哪些?学生平价蓝牙耳机推荐

你是否正在为选择一款性价比高的蓝牙耳机而烦恼&#xff1f;是否希望找到一款既适合学生使用&#xff0c;又能在预算内满足需求的蓝牙耳机&#xff1f;300元蓝牙耳机性价比高的有哪些&#xff1f;如果你有这样的需求&#xff0c;那么下面我将为大家提供一些有益的参考&#xff…

中间件安全(三)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 前言: 本文主要讲解apache命令执行漏洞&#xff08;cve_2021_41773&#xff09;。 靶场链接&#xff1a;Vulfocus 漏洞威胁分析平台 一&#xff0c;漏洞简介。 cve_2021_41773漏洞…

【STM32外设及其应用】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

pyvideotrans 最佳AI翻译软件

文章目录 体验视频翻译配音工具主要用途和功能预打包版本(仅win10/win11可用&#xff0c;MacOS/Linux系统使用源码部署)MacOS源码部署Linux 源码部署Window10/11 源码部署源码部署问题说明使用教程和文档语音识别模型:视频教程(第三方)软件预览截图相关联项目致谢 体验 不错&a…

【含开题报告+文档+PPT+源码】基于SpringBoot的健康知识学习分享平台的设计与实现

开题报告 随着人们生活水平的提高和健康意识的增强&#xff0c;健康知识在日常生活中的重要性日益凸显。传统的健康知识获取途径如书籍、讲座等虽然具有一定的效果&#xff0c;但存在信息更新慢、交互性差等局限性。同时&#xff0c;互联网的普及和移动互联网的发展为人们提供…