【Spring 事务和事务传播机制】

news2024/10/2 20:29:02

目录

1 事务概述

1.1 为什么需要事务

1.2 事务的特性

1.3 Spring 中事务的实现

2 Spring 声明式事务

2.1 @Transactional

2.2 @Transactional 的作用范围

2.3 @Transactional 的各种参数

2.3.1 ioslation 

2.4 事务发生了异常,也不回滚的情况

异常被捕获时

3 事务的传播机制 

3.1 定义

3.2 为什么需要事务传播机制

3.3 事务传播机制种类

Propagation.REQUIRED 

 Propagation.SUPPORTS 

 Propagation.MANDATORY

Propagation.REQUIRES_NEW

Propagation.NOT_SUPPORTED

Propagation.NEVER

Propagation.NESTED


1 事务概述

1.1 为什么需要事务

事务定义

将⼀组操作封装成⼀个执⾏单元(封装到⼀起),要么全部成功,要么全部失败。

对于转账来说:

第一步操作:A 账户 -1000 元

第二步操作:B 账户 +1000 元

使用了事务之后,这一组操作要么一起执行成功,要么一起失败。如果没有事务的情况下,有可能第一步成功了,第二步失败了,那么对于 A 来说,它的账户的 1000 块钱就人间蒸发了。

1.2 事务的特性

事务有4 ⼤特性(ACID),原⼦性、持久性、⼀致性和隔离性,具体概念如下:

原⼦性(Atomicity):⼀个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中 间某个环节。事务在执⾏过程中发⽣错误,会被回滚(Rollback)到事务开始前的状态,就像这个 事务从来没有执⾏过⼀样。

⼀致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写⼊的资料必须完 全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以⾃发性地完成预定的⼯ 作。

隔离性(Isolation):数据库允许多个并发事务同时对其数据进⾏读写和修改的能⼒,隔离性可以防⽌多个事务 并发执⾏时由于交叉执⾏⽽导致数据的不⼀致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串⾏化 (Serializable)。

持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

1.3 Spring 中事务的实现

Spring 中事务操作分为两类:

1. 编程式事务(手动写代码操作事务)

2. 声明式事务(利用注解自动开启和提交事务)

2 Spring 声明式事务

MySQL 中,事务有三个重要的操作:开启事务、提交事务、回滚事务,对应的操作命令如下:

-- 开启事务

start transaction;

 

-- 业务执行

  

-- 提交事务

commit;

  

-- 回滚事务

rollback;

而 Spring 声明式事务的实现与 MySQL 事务的实现基本一致,只是前者自动的,只需要在需要的⽅法上添加 @Transactional 注解就可以实现了,⽆需⼿动开启事务和提交事务,进⼊⽅法时⾃动开启事务,⽅法执⾏完会⾃动提交事务,如果中途发⽣了没有处理的异常会⾃动回滚事务。

2.1 @Transactional

package com.example.demo.model;

import lombok.Data;

import java.time.LocalDateTime;

@Data
public class UserInfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;
}
package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {
    @Insert("insert into userinfo(username,password) values(#{username},#{password})")
    int add(UserInfo userInfo);
}
package com.example.demo.service;

import com.example.demo.mapper.UserMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    public int add(UserInfo userInfo){
        return userMapper.add(userInfo);
    }
}
package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("莉丝");
        userInfo.setPassword("6363");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        int num = 10/0;
        // 3. 将结果给前端
        return 0;
    }
}

启动项目发现,使用了 @Transactional 注解的确回滚了事务:

 可以看到,信息并没有添加到数据库的 userinfo 这表里。

2.2 @Transactional 的作用范围

@Transactional 可以用来修饰方法或类,修饰方法时,只能应用到 public 方法上,其他访问权限均不生效;修饰类时,该注解对该类中所有的 public 方法都生效。

2.3 @Transactional 的各种参数

参数作用
value配置多个事务管理器时,使用该属性指定一个事务管理器
transactionManager
propagation事务的传播行为,默认值为 Propagation.REQUIRED
isolation事务的隔离级别,默认值为 Isolation.DEFAULT
timeout事务的超出时间,默认值为 -1。如果超出该时间限制但事务还没有完成,则自动回滚事务
readOnly是否为只读事务,默认值为 false;
rollbackFor指定触发事务回滚的异常类型,可以多个
rollbackForClassName指定触发事务回滚的异常类名称,可以多个
noRollbackFor指定不回滚事务的异常类型,可以多个
noRollbackForClassName指定不回滚事务的异常类名称,可以多个

2.3.1 ioslation 

根据文章开头的介绍,我们知道事务有四大特性,分别是原子性、一致性、隔离性以及持久性。而这四大特性中,只有隔离性,也就是隔离级别是可以设置的。

事务的隔离级别是用来保障多个并发事务执行更加可控,更符合程序员的预期。

在 Spring 中,可以通过 @Transactional 中的 isolation 属性进行设置。

MySQL 事务隔离级别:

1. READ UNCOMMITTED:读未提交,该隔离级别的事务可以看到其他事务中未提交的数据,⽽未提交的数据可能会发⽣回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。

2. READ COMMITTED:读已提交,该隔离级别的事务能读取到已经提交事务的数据, 因此它不会有脏读问题。但由于在事务的执⾏中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读。

3. REPEATABLE READ:可重复读,是 MySQL 的默认事务隔离级别,它能确保同⼀事务多次查询的结果⼀致,这就意味着,该级别的事务 A 正在执行,而另一个事务 B 成功插入了一条数据,但由于可重复读要保证每次查询的结果一致,所以 A 就会查询不到这条数据,但是 A 也想插入这条数据,却发现插入不了,这就是幻读。

4. SERIALIZABLE:序列化,事务最⾼隔离级别,它会强制事务排序,使之不会发⽣冲突,从⽽解决了脏读、不可重复读和幻读问题,但因为执⾏效率低,所以真正使⽤的场景并不多。

 

事务隔离级别脏读不可重复读幻读
读未提交
读已提交×
可重复读××
串行化×××

 

● 脏读:⼀个事务读取到了另⼀个事务修改的数据之后,后⼀个事务⼜进⾏了回滚操作,从⽽导致第⼀个事务读取的数据是错误的。

● 不可重复读:⼀个事务两次查询得到的结果不同,因为在两次查询中间,有另⼀个事务把数据修改了。

● 幻读:⼀个事务两次查询中得到的结果集不同,因为在两次查询中另⼀个事务有新增了⼀部分数据。

不同的数据库的隔离级别是不一样的,MySQL 有四种,Oracle 有三种。Spring 的隔离级别为五种,是为了兼容不同的数据库。

Spring 中事务隔离级别包含以下 5 种:

1. Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。

2. Isolation.READ_UNCOMMITTED:读未提交,可以读取到未提交的事务,存在脏读。

3. Isolation.READ_COMMITTED:读已提交,只能读取到已经提交的事务,解决了脏读,存在不可重复读。

4. Isolation.REPEATABLE_READ:可重复读,解决了不可重复读,但存在幻读(MySQL默认级别)。

​​​​​​​

5. Isolation.SERIALIZABLE:串⾏化,可以解决所有并发问题,但性能太低。

如果 Spring 的隔离级别与 MySQL 设置的隔离级别不同的时候,以 Spring 设置的隔离级别为主。

Spring 相当于一个客户端,设置了,以 Spring 设置的为主,没有设置时,跟连接的数据库的隔离级别一样,也就是 DEFAULT。

隔离级别枚举的值以 2 的次方,性能更高。

2.4 事务发生了异常,也不回滚的情况

异常被捕获时

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("莉丝");
        userInfo.setPassword("6363");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){

        }

        // 3. 将结果给前端
        return 0;
    }
}

 

@Transactional 是AOP,出现异常的时候,代理对象可以感知到异常,并进行事务的回滚。但如果异常被捕获了,外部的代理对象就感知不到了,就不会进行事务的回滚了。

对此有两种解决方案。

1. 将异常继续抛出去,让代理对象感知到异常,也就能自动的回滚事务了。

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("埃罗尔");
        userInfo.setPassword("9146");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){
            throw e;
        }

        // 3. 将结果给前端
        return 0;
    }
}

2.  使用代码,手动回滚事务

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("埃罗尔");
        userInfo.setPassword("9146");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        // 3. 将结果给前端
        return 0;
    }
}

 在网页没有报错的情况下,进行了事务的回滚。

3 事务的传播机制 

3.1 定义

Spring 事务传播机制定义了多个包含了事务的⽅法,相互调⽤时,事务是如何在这些⽅法间进⾏传递的。

3.2 为什么需要事务传播机制

事务隔离级别是保证多个并发事务执⾏的可控性的(稳定性的),⽽事务传播机制是保证⼀个事务在多个调⽤⽅法间的可控性的(稳定性的)。

8

 

3.3 事务传播机制种类

Propagation.REQUIRED 

默认的事务传播级别,如果当前存在事务,就加入这个事务(加入意味着成为这个外部事务的一部分),如果不存在事务,则会自己创建一个新的事务。与其他被调用的事务,要么一起提交事务,要么一起回滚事务。

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("埃罗尔");
        userInfo.setPassword("9146");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        // 3. 将结果给前端
        return 0;
    }
}
package com.example.demo.service;

import com.example.demo.mapper.UserMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public int add(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("add result -> " + result);
        insert(userInfo);
        return result;
    }

    @Transactional
    public int insert(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("insert result -> " + result);
        int num = 10 / 0;
        return result;
    }
}

add 调用两个加了@Transactional 的 service 的方法。

 Propagation.SUPPORTS 

如果当前存在事务(存在于别的方法开启的事务中,而不是自己启动事务),则加入该事务;如果没有,则以非事务的方式继续运行。

修改 insert 方法如下,添加 propagation 参数:

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.SUPPORTS)
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("埃罗尔");
        userInfo.setPassword("9146");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){
//            throw e;
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        // 3. 将结果给前端
        return 0;
    }
}

 对于上述 add 来说,它并没有存在于任何一个事务当中,所以它按照非事务的方式运行。

package com.example.demo.service;

import com.example.demo.mapper.UserMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.SUPPORTS)
    public int add(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("add result -> " + result);
        insert(userInfo);
        return result;
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public int insert(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("insert result -> " + result);
        int num = 10 / 0;
        return result;
    }


}

service 中, add 被 controller 调用,由于 controller 不存在事务,因此 add 也不存在于任何事务中,所以 add 按照非事务的方式运行,同样对于 insert 来说也是如此,按照非事务的方式运行。

运行结果是:添加了两条信息:

 

如果 controller 的 add 的事务传播机制改成 Propagation.REQUIRED ,其他两个方法不变,结果会怎么样呢?

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("埃罗尔");
        userInfo.setPassword("9146");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){
//            throw e;
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        // 3. 将结果给前端
        return 0;
    }
}

 Propagation.MANDATORY

mandatory 强制性的意思。如果当前存在事务,则加入该事务;如果没有事务,则抛出异常。

Propagation.REQUIRES_NEW

表示创建⼀个新的事务,如果当前存在事务,则把当前事务挂 起。也就是说不管外部⽅法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法会新开 启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。

Propagation.NOT_SUPPORTED

以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。

Propagation.NEVER

以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("埃罗尔");
        userInfo.setPassword("9146");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        try{
            int num = 10/0;
        }catch (Exception e){
//            throw e;
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        // 3. 将结果给前端
        return 0;
    }
}
package com.example.demo.service;

import com.example.demo.mapper.UserMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.NEVER)
    public int add(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("add result -> " + result);
        insert(userInfo);
        return result;
    }

    @Transactional(propagation = Propagation.NEVER)
    public int insert(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("insert result -> " + result);
        int num = 10 / 0;
        return result;
    }


}

 

运行结果: 

 不添加任何一条信息。

Propagation.NESTED

如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。

嵌套的事务不影响外部的事务。NESTED 嵌套 NESTED ,一个完蛋,所有的 NESTED 都完蛋。

package com.example.demo.controller;

import com.example.demo.model.UserInfo;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public  int add(){
        // 1. 非空判断
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("玛丽莲·梦露");
        userInfo.setPassword("18");
        // 2. 调用 service 执行添加
        int result = userService.add(userInfo);
        System.out.println("result:"+result);
        
        userService.insert(userInfo);

        // 3. 将结果给前端

        return 0;
    }
}
package com.example.demo.service;

import com.example.demo.mapper.UserMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.NESTED)
    public int add(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("add result -> " + result);
        return result;
    }

    @Transactional(propagation = Propagation.NESTED)
    public int insert(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("insert result -> " + result);
        try {
            int num = 10 / 0;
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        return result;
    }
}

如果 insert 方法写成以下这种形式,不但 insert 感知到了异常,调用方感知到了异常,就会造成总体回滚,这就意味着数据无法添加。

    @Transactional(propagation = Propagation.NESTED)
    public int insert(UserInfo userInfo){
        int result = userMapper.add(userInfo);
        System.out.println("insert result -> " + result);
        int num = 10 / 0;
        return result;
    }

而如果对 insert 进行手动回滚操作,这样只有 insert 感知到了异常,但是调用方并没有感知。

为什么把 insert 放在 add 里,也会回滚。


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

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

相关文章

运维Shell脚本小试牛刀(七):在函数文脚本件中调用另外一个脚本文件中函数|函数递归调用|函数后台执行

运维Shell脚本小试牛刀(一) 运维Shell脚本小试牛刀(二) 运维Shell脚本小试牛刀(三)::$(cd $(dirname $0); pwd)命令详解 运维Shell脚本小试牛刀(四): 多层嵌套if...elif...elif....else fi_蜗牛杨哥的博客-CSDN博客 Cenos7安装小火车程序动画 运维Shell脚本小试…

手写Spring:第8章-初始化和销毁方法

文章目录 一、目标:初始化和销毁方法二、设计:初始化和销毁方法三、实现:初始化和销毁方法3.1 工程结构3.2 Spring应用上下文和Bean对象扩展初始化和销毁类图3.3 定义初始化和销毁方法的接口3.3.1 定义初始化接口3.3.2 定义销毁接口3.3.3 定义…

【 OpenGauss源码学习 —— 列存储(analyze)(三)】

列存储(analyze) acquire_sample_rows 函数RelationGetNumberOfBlocks 函数BlockSampler_Init 函数anl_init_selection_state 函数BlockSampler_GetBlock 函数ReadBufferExtendedPageGetMaxOffsetNumber 函数HeapTupleSatisfiesVacuum 函数heapCopyTuple…

微软8月系统更新引发问题:虚拟内存分页文件出现错误

微软的八月系统更新引发了一系列问题,其中包括“UNSUPPORTED_PROCESSOR”蓝屏错误和文件管理器故障。尽管微软已经修复了前者,但据国外科技媒体Windows Latest报道,仍有用户反馈在非微星设备上出现“fault in nonpaged area”蓝屏错误。 如果…

信息技术 安全技术 信息安全管理测量

声明 本文是学习信息技术 安全技术 信息安全管理 测量. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 范围 为了评估按照GB/T 22080-2008规定实施的信息安全管理体系(Information Security Management System,简称ISMS&#…

STM32移植FAT文件系统

所谓“移植”,就是打通FAT源码和物理设备之间的软件接口。 FAT源码早就被公益组织给写好了,直接下载源码。但是FAT作为顶层应用程序,它需要面对的底层物理设备是不确定的,那么底层的物理设备驱动程序就需要程序员来自己写。物理设…

VMware虚拟机挂起后再关机出现问题,连接不上外网解决方法,ifconfig无ens33

原文地址 Centos7 重启后ens33消失(外部连接不上)Centos7 重启后ens33消失(外部连接不上)_ens33不见了_瘦身小蚂蚁的博客-CSDN博客 解决方法:执行以下4个命令。 systemctl stop NetworkManager # 关闭NetworkManage…

《DevOps实践指南》- 读书笔记(二)

DevOps实践指南 Part 2 从何处开始5. 选择合适的价值流作为切入点5.1 绿地项目与棕地项目5.2 兼顾记录型系统和交互型系统5.3 从最乐于创新的团队开始5.4 扩大 DevOps 的范围5.5 小结 6. 理解、可视化和运用价值流6.1 确定创造客户价值所需的团队6.2 针对团队工作绘制价值流图6…

优思学院|精益生产与柔性制造:现代制造业的双重理念

现代制造业正不断演进,出现了许多新的生产理念和方法。在这其中,精益生产和柔性制造是两个引人注目且重要的理念。这两者不仅对企业的生产流程产生了深远的影响,还在提高效率、适应市场需求方面发挥着关键作用。 理念背景和核心原则 精益生…

pcd格式转ot/bt

1.具体实现可以看高博的bloghttps://www.cnblogs.com/gaoxiang12/p/5041142.html 2.问题:在编译octomap_tutor 源码时会报错。 修改方法:把cmakelists.txt里的c11改成c14

Android 文字转语音播放实现

1,TextToSpeech类是android自带的,但是部分设备需要支持TTS需要增加语音库,我使用的是讯飞语音(离线的哦)。请自行下载并安装讯飞语音APK,然后到系统设置中设置TTS功能默认使用该选项。有自带TTS库的可以省…

数字图像处理-图像压缩

数字图像处理-图像压缩 一、图像压缩1.1 图像压缩的意义1.2 图像的冗余信息1.2.1 编码冗余1.2.2 空间冗余1.2.3 时间冗余 二、一些基本的压缩方法2.1 霍夫曼编码2.2 行程编码2.3 算术编码2.4 LZW编码 三、数字图像水印3.1 简单的可见水印3.2LSB不可见水印 一、图像压缩 1.1 图…

亚马逊美国站干粉灭火器UL安全测试标准要求UL299测试报告

UL299干粉灭火器是一种常见的灭火设备,外观一般为红色罐体,装有干粉灭火剂。它主要以高速喷射干粉灭火剂来抑制火灾并起到灭火作用。该灭火器采用压力容器和喷射装置,具有紧凑结构、方便携带等特点。对于想要在亚马逊美国站上架干粉灭火器的卖…

SpingBoot整合Sa-Token框架(1)

一、文档参考:框架介绍 (sa-token.cc) 框架生态——开源项目 (sa-token.cc) 二、与SpingBoot整合 1、创建项目 在 IDE 中新建一个 SpringBoot 项目,例如:sa-token-demo-springboot(不会的同学请自行百度或者参考:Sp…

在EC2上对SELinux故障进行紧急恢复以及排查的思路及方法

概述 SELinux,全称Security-Enhanced Linux,是一个为系统提供强制访问控制机制的安全模块,安装并启用SELinux模块的操作系统会为每个进程和系统资源打上一个特殊的安全标记,称为SELinux上下文,并根据SELinux上下文信息…

高阶数据结构-----三种平衡树的实现以及原理(未完成)

TreeMap和TreeSet的底层实现原理就是红黑树 一)AVL树: 1)必须是一棵搜索树:前提是二叉树,任取一个节点,它的左孩子的Key小于父亲节点的Key小于右孩子节点的Key,中序遍历是有序的,按照Key的大小进行排列,高度平衡的二叉…

WINGREEN 034STM4-00-200-RS 输入输出模块

WINGREEN 034STM4-00-200-RS 输入输出模块是一种工业自动化设备,通常用于各种应用领域,以实现数字输入和输出功能。这些模块可以在不同行业的自动化系统中发挥关键作用,以下是一些可能的应用领域: 制造业:WINGREEN 034…

kubeadm搭建kubernetes(k8s)

kubeadm搭建kubernetes(k8s) 一、环境准备1.所有节点,关闭防火墙规则,关闭selinux,关闭swap交换2.修改主机名3.所有节点修改hosts文件4.调整内核参数5.生效参数 二、 安装软件1.所有节点安装docker2.所有节点安装kubea…

机器学习开源工具BatteryML,一站式分析与预测电池性能

编者按:天下苦锂电池寿命久矣,时闻“开车出,推车回”,又闻“充电两小时,待机两分钟”,亦闻“气温骤降,请注意电池保暖”……随着以锂离子电池为动力源的产品,如手机、电脑、新能源汽…

基于Java+SpringBoot+Vue前后端分离人事管理系统设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…