《Spring Boot 测试框架指南:@SpringBootTest与Mockito的最佳实践》

news2025/7/16 2:43:13

大家好呀!👋 今天我要和大家聊聊Spring Boot测试的那些事儿。作为一名Java开发者,写代码很重要,但写测试同样重要!💯 想象一下,你建了一座漂亮的房子🏠,但如果没有质量检查,你敢住进去吗?测试就是我们的"质量检查员"!今天重点介绍两个超级明星:@SpringBootTest和Mockito,保证让你学得明明白白!😊

📚 第一章:为什么要写测试?测试有多重要?

1.1 测试的重要性

先讲个小故事📖:小明写了一个计算器程序,能算加减乘除。他自信满满地交给老师,结果老师输入"5÷0",程序直接崩溃了💥!如果有测试,这种问题早就能发现啦!

测试的好处多多:

  • 🛡️ 防错保护:提前发现bug,避免上线后出问题
  • 🔄 安全重构:改代码时不担心破坏原有功能
  • 📝 文档作用:测试用例本身就是最好的使用示例
  • 持续集成:自动化测试是CI/CD的基础

1.2 Spring Boot测试生态

Spring Boot提供了一整套测试工具:

  • 🧪 @SpringBootTest:完整应用上下文测试
  • 🎭 Mockito:模拟对象和行为
  • 🏗️ TestEntityManager:数据库测试
  • 🌐 WebTestClient:WebFlux测试
  • 🖥️ MockMvc:Web MVC测试

今天我们先重点聊聊@SpringBootTest和Mockito这对黄金搭档!✨

🚀 第二章:@SpringBootTest - 你的应用完整测试工具

2.1 什么是@SpringBootTest?

@SpringBootTest就像是给你的Spring Boot应用做全身检查👨⚕️。它会启动几乎整个应用上下文,包括所有的bean、配置、数据库连接等等。

@SpringBootTest
class MyApplicationTests {
    
    @Autowired
    private MyService myService; // 可以自动注入真实的bean
    
    @Test
    void contextLoads() {
        assertThat(myService).isNotNull();
    }
}

2.2 @SpringBootTest的几种模式

@SpringBootTest有三种启动模式,就像汽车的档位🚗:

  1. MOCK(默认):模拟Servlet环境,不启动真实服务器

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
    
  2. RANDOM_PORT:启动真实服务器,随机端口

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    
  3. DEFINED_PORT:使用application.properties中定义的端口

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    
  4. NONE:不提供任何Servlet环境

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
    

2.3 实际应用示例

假设我们有个用户服务:

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User getUserById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found"));
    }
}

测试这个服务:

@SpringBootTest
class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    void shouldGetUserById() {
        // 准备测试数据
        User testUser = new User(1L, "张三");
        userRepository.save(testUser);
        
        // 执行测试
        User result = userService.getUserById(1L);
        
        // 验证结果
        assertThat(result.getName()).isEqualTo("张三");
    }
    
    @Test
    void shouldThrowExceptionWhenUserNotFound() {
        assertThatThrownBy(() -> userService.getUserById(999L))
            .isInstanceOf(UserNotFoundException.class)
            .hasMessageContaining("User not found");
    }
}

2.4 最佳实践

  1. 合理选择web环境:根据测试需求选择MOCK、RANDOM_PORT或NONE
  2. 使用@TestConfiguration:覆盖特定bean而不是全部配置
  3. 注意测试顺序:使用@DirtiesContext确保测试独立性
  4. 控制测试范围:不要过度使用@SpringBootTest,轻量级测试更高效

🎭 第三章:Mockito - 测试中的"替身演员"

3.1 什么是Mockito?

Mockito就像是电影里的替身演员🎬,它可以:

  • 创建虚拟对象(模拟对象)
  • 定义这些对象的行为
  • 验证它们是否被正确调用

为什么需要Mockito?因为单元测试应该独立!我们不希望测试UserService时,真的去调用数据库或第三方API。

3.2 Mockito核心功能

3.2.1 创建Mock对象
// 创建一个模拟的UserRepository
UserRepository mockRepo = Mockito.mock(UserRepository.class);

或者使用注解更简洁:

@Mock
private UserRepository userRepository;

@BeforeEach
void setup() {
    MockitoAnnotations.openMocks(this); // 初始化@Mock注解
}
3.2.2 定义Mock行为
// 当调用findById(1L)时,返回预设的用户
Mockito.when(userRepository.findById(1L))
    .thenReturn(Optional.of(new User(1L, "张三")));

// 当调用findById(999L)时,返回空
Mockito.when(userRepository.findById(999L))
    .thenReturn(Optional.empty());
3.2.3 验证交互
// 验证findById(1L)被调用了一次
Mockito.verify(userRepository, Mockito.times(1))
    .findById(1L);

// 验证deleteById从未被调用
Mockito.verify(userRepository, Mockito.never())
    .deleteById(Mockito.anyLong());

3.3 Mockito与@SpringBootTest结合

使用@MockBean替换Spring上下文中的真实bean:

@SpringBootTest
class UserServiceMockTest {
    
    @Autowired
    private UserService userService; // 真实服务
    
    @MockBean
    private UserRepository userRepository; // 模拟仓库
    
    @Test
    void shouldGetUserByIdWithMock() {
        // 设置模拟行为
        Mockito.when(userRepository.findById(1L))
            .thenReturn(Optional.of(new User(1L, "张三")));
        
        // 调用真实服务方法
        User result = userService.getUserById(1L);
        
        // 验证
        assertThat(result.getName()).isEqualTo("张三");
        Mockito.verify(userRepository).findById(1L);
    }
}

3.4 Mockito高级技巧

3.4.1 参数匹配器
// 任何Long类型的ID
Mockito.when(userRepository.findById(Mockito.anyLong()))
    .thenReturn(Optional.of(new User(1L, "默认用户")));

// 特定条件的参数
Mockito.when(userRepository.findByName(Mockito.argThat(name -> name.length() > 5)))
    .thenReturn(Optional.of(new User(1L, "长名字用户")));
3.4.2 抛出异常
Mockito.when(userRepository.save(Mockito.any()))
    .thenThrow(new RuntimeException("数据库错误"));
3.4.3 连续调用不同结果
Mockito.when(userRepository.count())
    .thenReturn(10L)  // 第一次调用返回10
    .thenReturn(20L)  // 第二次返回20
    .thenThrow(new RuntimeException("太多调用")); // 第三次抛出异常
3.4.4 验证调用顺序
InOrder inOrder = Mockito.inOrder(userRepository);

// 验证先调用findById,再调用save
inOrder.verify(userRepository).findById(1L);
inOrder.verify(userRepository).save(Mockito.any(User.class));

3.5 Mockito最佳实践

  1. 不要过度Mock:只Mock必要的依赖
  2. 验证适度:不要过度验证内部实现
  3. 保持简单:每个测试只关注一个行为
  4. 使用@Spy谨慎:@Spy是部分Mock,可能导致测试不稳定

🔧 第四章:测试中的常见问题与解决方案

4.1 测试速度慢怎么办?

@SpringBootTest启动整个应用,确实会比较慢🐢。解决方案:

  • 使用**@DataJpaTest**、@WebMvcTest等切片测试
  • 合理使用**@MockBean**减少真实bean加载
  • 共享测试上下文:@SpringBootTest + @DirtiesContext

4.2 数据库测试问题

测试时操作数据库📊要注意:

  • 使用嵌入式数据库(H2)加速测试
  • 每个测试后清理数据:
    @Transactional
    @Rollback  // 默认就是true
    @Test
    void testWithDatabase() { ... }
    
  • 或者手动清理:
    @AfterEach
    void tearDown() {
        userRepository.deleteAll();
    }
    

4.3 第三方服务依赖

对于外部API调用🌐:

  • 使用Mockito模拟
  • 使用WireMock模拟HTTP服务
  • 考虑契约测试(Pact)

4.4 测试Spring MVC

测试Controller层🖥️:

@WebMvcTest(UserController.class)
class UserControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @MockBean
    private UserService userService;
    
    @Test
    void shouldReturnUser() throws Exception {
        Mockito.when(userService.getUserById(1L))
            .thenReturn(new User(1L, "张三"));
            
        mockMvc.perform(MockMvcRequestBuilders.get("/users/1"))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("张三"));
    }
}

🏆 第五章:测试金字塔与策略

5.1 测试金字塔

健康的测试套件应该像金字塔🏛️:

  1. 单元测试(70%):测试单个类,快速执行
  2. 集成测试(20%):测试组件间交互
  3. 端到端测试(10%):测试完整应用流程

5.2 如何选择测试工具

测试类型适用场景推荐工具
纯业务逻辑Service层核心逻辑JUnit + Mockito
数据库交互Repository层@DataJpaTest + TestEntityManager
Web层Controller@WebMvcTest + MockMvc
完整流程应用启动到API调用@SpringBootTest + TestRestTemplate
客户端交互前端调用API@SpringBootTest + WebTestClient

5.3 测试命名规范

好的测试名应该像说明书📝:

  • 方法名说明测试场景和预期
  • 常用模式:[方法名]_[状态]_[预期]

例如:

@Test
void getUserById_withInvalidId_shouldThrowException() { ... }

@Test
void saveUser_withValidUser_shouldReturnSavedUser() { ... }

🛠️ 第六章:实战演练 - 完整测试示例

让我们通过一个完整的用户管理系统示例来实践:

6.1 领域模型

@Entity
public class User {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private String email;
    // getters/setters
}

public interface UserRepository extends JpaRepository {
    Optional findByEmail(String email);
}

6.2 服务层

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User registerUser(String name, String email) {
        if (userRepository.findByEmail(email).isPresent()) {
            throw new EmailAlreadyExistsException("Email already registered");
        }
        
        User user = new User();
        user.setName(name);
        user.setEmail(email);
        return userRepository.save(user);
    }
    
    public User getUserByEmail(String email) {
        return userRepository.findByEmail(email)
            .orElseThrow(() -> new UserNotFoundException("User not found"));
    }
}

6.3 完整的测试套件

6.3.1 单元测试(Service层)
class UserServiceUnitTest {
    
    private UserService userService;
    
    @Mock
    private UserRepository userRepository;
    
    @BeforeEach
    void setUp() {
        userService = new UserService(userRepository);
    }
    
    @Test
    void registerUser_withNewEmail_shouldSaveUser() {
        // 准备
        String name = "张三";
        String email = "zhangsan@example.com";
        
        // 模拟findByEmail返回空
        Mockito.when(userRepository.findByEmail(email))
            .thenReturn(Optional.empty());
        
        // 模拟save返回用户
        User savedUser = new User(1L, name, email);
        Mockito.when(userRepository.save(Mockito.any(User.class)))
            .thenReturn(savedUser);
        
        // 执行
        User result = userService.registerUser(name, email);
        
        // 验证
        assertThat(result.getId()).isNotNull();
        assertThat(result.getEmail()).isEqualTo(email);
        
        // 验证交互
        Mockito.verify(userRepository).findByEmail(email);
        Mockito.verify(userRepository).save(Mockito.any(User.class));
    }
    
    @Test
    void registerUser_withExistingEmail_shouldThrowException() {
        String email = "exists@example.com";
        
        // 模拟已存在用户
        Mockito.when(userRepository.findByEmail(email))
            .thenReturn(Optional.of(new User()));
            
        // 执行并验证异常
        assertThatThrownBy(() -> userService.registerUser("任何名字", email))
            .isInstanceOf(EmailAlreadyExistsException.class)
            .hasMessageContaining("Email already registered");
    }
}
6.3.2 集成测试(Repository层)
@DataJpaTest
class UserRepositoryIntegrationTest {
    
    @Autowired
    private TestEntityManager entityManager;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    void findByEmail_whenUserExists_shouldReturnUser() {
        // 保存测试用户
        User user = new User(null, "李四", "lisi@example.com");
        entityManager.persist(user);
        entityManager.flush();
        
        // 查询
        Optional found = userRepository.findByEmail(user.getEmail());
        
        // 验证
        assertThat(found).isPresent();
        assertThat(found.get().getName()).isEqualTo("李四");
    }
    
    @Test
    void findByEmail_whenUserNotExists_shouldReturnEmpty() {
        Optional found = userRepository.findByEmail("nonexistent@example.com");
        assertThat(found).isEmpty();
    }
}
6.3.3 完整集成测试
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class UserSystemIntegrationTest {
    
    @LocalServerPort
    private int port;
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Autowired
    private UserRepository userRepository;
    
    @AfterEach
    void tearDown() {
        userRepository.deleteAll();
    }
    
    @Test
    void fullUserRegistrationFlow_shouldWork() {
        // 准备注册请求
        Map request = new HashMap<>();
        request.put("name", "王五");
        request.put("email", "wangwu@example.com");
        
        // 调用注册API
        ResponseEntity response = restTemplate.postForEntity(
            "http://localhost:" + port + "/api/users",
            request,
            User.class);
            
        // 验证响应
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        assertThat(response.getBody().getId()).isNotNull();
        assertThat(response.getBody().getEmail()).isEqualTo("wangwu@example.com");
        
        // 验证数据库
        Optional dbUser = userRepository.findByEmail("wangwu@example.com");
        assertThat(dbUser).isPresent();
        
        // 调用查询API
        ResponseEntity getResponse = restTemplate.getForEntity(
            "http://localhost:" + port + "/api/users?email=wangwu@example.com",
            User.class);
            
        assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(getResponse.getBody().getName()).isEqualTo("王五");
    }
}

🎯 第七章:测试覆盖率与质量门禁

7.1 测试覆盖率

测试覆盖率是衡量测试完整性的重要指标📊:

  • 行覆盖率:执行了多少百分比代码行
  • 分支覆盖率:是否覆盖了所有if-else分支
  • 变异测试:更高级的覆盖率分析

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 什么是 Cookie?简单介绍与使用方法

  • 什么是 Session?如何应用?

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • 如何理解应用 Java 多线程与并发编程?

  • 把握Java泛型的艺术:协变、逆变与不可变性一网打尽

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 如何理解线程安全这个概念?

  • 理解 Java 桥接方法

  • Spring 整合嵌入式 Tomcat 容器

  • Tomcat 如何加载 SpringMVC 组件

  • “在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”

  • “避免序列化灾难:掌握实现 Serializable 的真相!(二)”

  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

  • 解密 Redis:如何通过 IO 多路复用征服高并发挑战!

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”

  • Java 中消除 If-else 技巧总结

  • 线程池的核心参数配置(仅供参考)

  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)

  • Java 枚举的几个常用技巧,你可以试着用用

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)

  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)

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

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

相关文章

【计算机视觉】OpenCV项目实战- Artificial-Eyeliner 人脸眼线检测

Artificial-Eyeliner 人脸眼线检测 项目介绍运行方式运行步骤常见问题及解决方法1. dlib 安装失败其他注意事项 2. 缺少 make / gcc3. **依赖库安装问题**&#xff1a;4. *人脸关键点检测失败&#xff1a;5. 眼线效果不理想&#xff1a;6. 实时处理延迟&#xff1a;7. 保存文件…

工作总结(十二)——迁移svn单项目到gitlab上,保留历史提交记录

文章目录 前言一、目的二、操作步骤1.创建项目库2.复制历史提交者账号3.复制待迁移项目以及历史记录4.push到gitlab远程仓库 总结 前言 本系列文章主要记录工作中一些需要记录的内容 一、目的 因为一些原因&#xff0c;我需要将svn库上的某个项目迁移到公司的gitlab库管理平台…

Git Flow

Git Flow深度解析&#xff1a;企业级分支管理实战指南 前言 在持续交付时代&#xff0c;分支策略决定团队协作效率。Git Flow作为经典的分支管理模型&#xff0c;被Apache、Spring等知名项目采用。2023年JetBrains开发者调查报告显示&#xff0c;Git Flow仍是中大型项目最常用…

Flink介绍——实时计算核心论文之Kafka论文详解

引入 我们通过S4和Storm论文的以下文章&#xff0c;已经对S4和Storm有了不错的认识&#xff1a; S4论文详解S4论文总结Storm论文详解Storm论文总结 不过&#xff0c;在讲解这两篇论文的时候&#xff0c;我们其实没有去搞清楚对应的流式数据是从哪里来的。虽然S4里有Keyless …

AI Agents系列之构建多智能体系统

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…

OJ笔试强训_1至24天

OJ笔试强训 Day01 [NOIP2010]数字统计_牛客题霸_牛客网 点击消除_牛客题霸_牛客网 两个数组的交集_牛客题霸_牛客网 Day02 牛牛的快递_牛客题霸_牛客网 最小花费爬楼梯_牛客题霸_牛客网 数组中两个字符串的最小距离__牛客网 Day03 简写单词_牛客题霸_牛客网 dd爱框框_…

3款顶流云电脑与传统电脑性能PK战:START云游戏/无影云/ToDesk云电脑谁更流畅?

这里写目录标题 一、前言二、本地机器配置环境三、START云游戏/无影云/ToDesk云电脑配置对比3.1 START云游戏3.2 无影云个人版3.3 ToDesk云电脑 四、本地电脑与云电脑性能实战4.1 游戏场景体验4.1.1 本地电脑测试4.1.2 云电脑测试英雄联盟黑神话悟空其他游戏 4.2 主流设计场景体…

java IO/NIO/AIO

(✪▽✪)曼波~~~~&#xff01;让曼波用最可爱的赛马娘方式给你讲解吧&#xff01;(⁄ ⁄•⁄ω⁄•⁄ ⁄) &#x1f3a0;曼波思维导图大冲刺&#xff08;先看框架再看细节哦&#xff09;&#xff1a; &#x1f4da; 解释 Java 中 IO、NIO、AIO 的区别和适用场景&#xff1a; …

java输出、输入语句

先创建一个用于测试的java 编写程序 #java.util使java标准库的一个包&#xff0c;这里拉取Scanner类 import java.util.Scanner;public class VariableTest {public static void main(String[] args) {#创建一个 Scanner 对象Scanner scanner new Scanner(System.in);System.…

宏基因组产品升级——抗菌肽数据库APD

抗菌肽&#xff08;Antimicrobial Peptides&#xff0c;简称AMPs&#xff09;是一类存在于多种生物体中的天然分子。它们在抵御微生物感染中扮演着重要角色&#xff0c;发挥着先天免疫反应的作用。抗菌肽功能分类广泛&#xff0c;包括&#xff1a;抗菌&#xff0c;抗生物膜&…

线程池七个参数的含义

Java中的线程池里七个参数的以及其各自的含义 面试题&#xff1a;说一下线程池七个参数的含义&#xff1f; 所谓的线程池的 7 大参数是指&#xff0c;在使用 ThreadPoolExecutor 创建线程池时所设置的 7 个参数&#xff0c;如以下源码所示&#xff1a; public ThreadPoolExe…

Windows suwellofd 阅读器-v5.0.25.0320

Windows suwellofd 阅读器 链接&#xff1a;https://pan.xunlei.com/s/VOO7tUkTHHTTjSe39CeVkUHbA1?pwd3ibx# OFD(Open Fixed-layout Document) &#xff0c; 数科OFD阅读器支持国标版式、可信阅读、是电子发票、电子证照&#xff0c;电子病历等电子文件理想阅读工具。 多格…

三大等待和三大切换

三大等待 1、三大等待&#xff1a;等待的方式有三种&#xff1a;强制等待&#xff0c;隐性等待&#xff0c;显性等待。 1、强制等待&#xff1a;time.sleep(2)&#xff0c;秒 优点&#xff1a;使用简单缺点&#xff1a;等待时间把握不准&#xff0c;容易造成时间浪费或者等待时…

告别定时任务!用Dagster监听器实现秒级数据响应自动化

在数据管道开发中&#xff0c;我们经常面临需要根据外部事件触发计算任务的场景。传统基于时间的调度方式存在资源浪费和时效性不足的问题。本文将通过Dagster的**传感器&#xff08;Sensor&#xff09;**功能&#xff0c;演示如何构建事件驱动的数据处理流程。 场景模拟&…

【Unity】打包TextMeshPro的字体

前言 在Unity中&#xff0c;TextMeshPro与常规 Text 组件相比提供了更高级的文本呈现功能&#xff0c;TextMesh Pro 可以处理各种语言&#xff0c;包括中文。我们可以轻松地在 Unity 项目中使用中文&#xff0c;而不必担心字体和布局问题。TextMeshPro需要的字体资源就需要我们…

51单片机实验五:A/D和D/A转换

一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. 器材&#xff1a;TX-1C单片机&#xff08;STC89C52RC&#xff09;、电脑。 二、 实验内容及实验步骤 1.A/D转换 概念&#xff1a;模数转换是将连续的模拟信号转换为离散的数字信…

使用VHD虚拟磁盘安装双系统,避免磁盘分区

前言 很多时候&#xff0c;我们对现在的操作系统不满意,就想要自己安装一个双系统 但是安装双系统又涉及到硬盘分区,非常复杂,容易造成数据问题 虚拟机的话有经常用的不爽,这里其实有一个介于虚拟机和双系统之间的解决方法,就是使用虚拟硬盘文件安装系统. 相当于系统在机上…

Kafka消费者端重平衡流程

重平衡的完整流程需要消费者 端和协调者组件共同参与才能完成。我们先从消费者的视角来审视一下重平衡的流程。在消费者端&#xff0c;重平衡分为两个步骤&#xff1a;分别是加入组和等待领导者消费者&#xff08;Leader Consumer&#xff09;分配方案。这两个步骤分别对应两类…

Django之modelform使用

Django新增修改数据功能优化 目录 1.新增数据功能优化 2.修改数据功能优化 在我们做数据优化处理之前, 我们先回顾下传统的写法, 是如何实现增加修改的。 我们需要在templates里面新建前端的页面, 需要有新增还要删除, 比如说员工数据的新增, 那需要有很多个输入框, 那html…

云轴科技ZStack入选中国人工智能产业发展联盟《大模型应用交付供应商名录》

2025年4月8日至9日&#xff0c;中国人工智能产业发展联盟&#xff08;以下简称AIIA&#xff09;第十四次全体会议暨人工智能赋能新型工业化深度行&#xff08;南京站&#xff09;在南京召开。工业和信息化部科技司副司长杜广达&#xff0c;中国信息通信研究院院长、中国人工智能…