《软件工程》第 12 章 - 软件测试

软件测试是确保软件质量的关键环节,它通过执行程序来发现错误,验证软件是否满足需求。本章将依据目录,结合 Java 代码示例、可视化图表,深入讲解软件测试的概念、过程、方法及实践。

12.1 软件测试的概念

12.1.1 软件测试的任务

软件测试的主要任务是:

  1. 发现错误 :通过执行程序,找出代码中的缺陷和逻辑错误。
  2. 验证功能:确保软件满足用户需求和规格说明。
  3. 评估质量:对软件的可靠性、性能等质量属性进行评估。

12.1.2 测试阶段的信息流程

测试阶段的信息流程:

展示测试过程中的信息流转。

12.1.3 测试用例及其设计

测试用例是为测试而设计的一组输入和预期输出,用于验证软件的特定功能。例如,测试一个简单的加法函数的测试用例:

复制代码
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

// 对应的测试用例(使用JUnit框架)
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CalculatorTest {
    @Test
    public void testAddPositiveNumbers() {
        Calculator calculator = new Calculator();
        int result = calculator.add(3, 5);
        assertEquals(8, result); // 预期结果为8
    }

    @Test
    public void testAddNegativeNumbers() {
        Calculator calculator = new Calculator();
        int result = calculator.add(-3, -5);
        assertEquals(-8, result); // 预期结果为-8
    }
}

12.1.4 软件测试的原则

软件测试应遵循以下原则:

  1. 尽早测试:测试应从软件开发的早期阶段开始,如需求分析和设计阶段。
  2. 全面测试覆盖所有可能的输入和场景,包括边界条件和异常情况
  3. 避免自测:开发人员应避免测试自己编写的代码,减少主观因素影响。
  4. 记录测试结果:详细记录测试过程和结果,便于追踪和分析。

12.2 软件测试的过程模型

软件测试的过程模型通常与软件开发过程模型对应,常见的有 V 模型、W 模型等。以 V 模型为例:

展示 V 模型中测试阶段与开发阶段的对应关系。

12.3 软件测试方法

12.3.1 白盒测试

白盒测试基于代码的内部结构和逻辑,主要技术包括:

  • 语句覆盖:确保每个语句至少执行一次。
  • 判定覆盖:确保每个判定的真假分支至少执行一次。
  • 条件覆盖:确保每个判定中的每个条件的可能取值至少执行一次。

示例代码及测试用例:

复制代码
public class ControlFlow {
    public boolean checkNumber(int num) {
        if (num > 10 && num % 2 == 0) {
            return true;
        } else {
            return false;
        }
    }
}

// 白盒测试用例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class ControlFlowTest {
    @Test
    public void testCheckNumberTrue() {
        ControlFlow cf = new ControlFlow();
        assertTrue(cf.checkNumber(12)); // 覆盖true分支
    }

    @Test
    public void testCheckNumberFalse1() {
        ControlFlow cf = new ControlFlow();
        assertFalse(cf.checkNumber(5)); // 覆盖false分支(num <= 10)
    }

    @Test
    public void testCheckNumberFalse2() {
        ControlFlow cf = new ControlFlow();
        assertFalse(cf.checkNumber(11)); // 覆盖false分支(num为奇数)
    }
}

12.3.2 黑盒测试

黑盒测试基于软件的外部功能和需求,不考虑内部实现。主要技术包括:

  • 等价类划分:将输入域划分为若干等价类,从每个等价类中选取代表性值作为测试用例。
  • 边界值分析:选择输入域的边界值作为测试用例,如最小值、最大值、刚好超过边界的值。
  • 错误推测法:基于经验和直觉推测可能的错误,设计针对性的测试用例。

以三角形分类函数为例:

复制代码
public class TriangleClassifier {
    public String classify(int a, int b, int c) {
        // 检查是否构成三角形
        if (a <= 0 || b <= 0 || c <= 0 || a + b <= c || a + c <= b || b + c <= a) {
            return "非三角形";
        }
        // 检查等边三角形
        if (a == b && b == c) {
            return "等边三角形";
        }
        // 检查等腰三角形
        if (a == b || a == c || b == c) {
            return "等腰三角形";
        }
        // 普通三角形
        return "普通三角形";
    }
}

// 黑盒测试用例(等价类划分和边界值分析)
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class TriangleClassifierTest {
    @Test
    public void testEquilateralTriangle() {
        TriangleClassifier tc = new TriangleClassifier();
        assertEquals("等边三角形", tc.classify(3, 3, 3));
    }

    @Test
    public void testIsoscelesTriangle() {
        TriangleClassifier tc = new TriangleClassifier();
        assertEquals("等腰三角形", tc.classify(3, 3, 4));
    }

    @Test
    public void testScaleneTriangle() {
        TriangleClassifier tc = new TriangleClassifier();
        assertEquals("普通三角形", tc.classify(3, 4, 5));
    }

    @Test
    public void testNotTriangle() {
        TriangleClassifier tc = new TriangleClassifier();
        assertEquals("非三角形", tc.classify(1, 2, 3));
    }

    @Test
    public void testBoundaryValues() {
        TriangleClassifier tc = new TriangleClassifier();
        assertEquals("非三角形", tc.classify(0, 3, 4)); // 边界值0
        assertEquals("等腰三角形", tc.classify(2, 2, 4)); // 边界值a+b=c
    }
}

12.4 软件测试活动及实施策略

12.4.1 单元测试

单元测试是对软件中的最小可测试单元(如方法、类)进行测试。例如,测试一个栈类的基本操作:

复制代码
import java.util.EmptyStackException;

public class Stack {
    private int[] array;
    private int top;
    private int capacity;

    public Stack(int capacity) {
        this.capacity = capacity;
        this.array = new int[capacity];
        this.top = -1;
    }

    public void push(int item) {
        if (top == capacity - 1) {
            throw new StackOverflowError("栈已满");
        }
        array[++top] = item;
    }

    public int pop() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return array[top--];
    }

    public int peek() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return array[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }
}

// 单元测试用例
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class StackTest {
    private Stack stack;

    @BeforeEach
    public void setUp() {
        stack = new Stack(5);
    }

    @Test
    public void testPushAndPop() {
        stack.push(10);
        stack.push(20);
        assertEquals(20, stack.pop());
        assertEquals(10, stack.pop());
    }

    @Test
    public void testPeek() {
        stack.push(10);
        assertEquals(10, stack.peek());
        assertEquals(10, stack.peek()); // 多次peek不应改变栈
    }

    @Test
    public void testEmptyStack() {
        assertTrue(stack.isEmpty());
        assertThrows(EmptyStackException.class, () -> stack.pop());
        assertThrows(EmptyStackException.class, () -> stack.peek());
    }

    @Test
    public void testStackOverflow() {
        for (int i = 0; i < 5; i++) {
            stack.push(i);
        }
        assertThrows(StackOverflowError.class, () -> stack.push(5));
    }
}

12.4.2 集成测试

集成测试是将多个单元组合成更大的模块进行测试,验证模块间的交互。例如,测试一个简单的订单处理系统:

复制代码
// 订单类
public class Order {
    private String orderId;
    private double totalAmount;
    private boolean paid;

    public Order(String orderId, double totalAmount) {
        this.orderId = orderId;
        this.totalAmount = totalAmount;
        this.paid = false;
    }

    public String getOrderId() {
        return orderId;
    }

    public double getTotalAmount() {
        return totalAmount;
    }

    public boolean isPaid() {
        return paid;
    }

    public void setPaid(boolean paid) {
        this.paid = paid;
    }
}

// 支付服务接口
public interface PaymentService {
    boolean processPayment(double amount);
}

// 订单处理服务
public class OrderService {
    private PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public boolean checkout(Order order) {
        if (order.isPaid()) {
            return false;
        }
        boolean paymentResult = paymentService.processPayment(order.getTotalAmount());
        if (paymentResult) {
            order.setPaid(true);
            return true;
        }
        return false;
    }
}

// 集成测试用例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

public class OrderServiceIntegrationTest {
    @Test
    public void testCheckoutSuccess() {
        // 创建模拟的支付服务
        PaymentService paymentService = mock(PaymentService.class);
        when(paymentService.processPayment(100.0)).thenReturn(true);

        // 创建订单服务并注入模拟的支付服务
        OrderService orderService = new OrderService(paymentService);
        Order order = new Order("ORD123", 100.0);

        // 执行测试
        boolean result = orderService.checkout(order);

        // 验证结果
        assertTrue(result);
        assertTrue(order.isPaid());
        verify(paymentService, times(1)).processPayment(100.0);
    }

    @Test
    public void testCheckoutFailure() {
        PaymentService paymentService = mock(PaymentService.class);
        when(paymentService.processPayment(100.0)).thenReturn(false);

        OrderService orderService = new OrderService(paymentService);
        Order order = new Order("ORD123", 100.0);

        boolean result = orderService.checkout(order);

        assertFalse(result);
        assertFalse(order.isPaid());
        verify(paymentService, times(1)).processPayment(100.0);
    }
}

12.4.3 确认测试

确认测试验证软件是否满足用户需求和规格说明,通常包括功能测试、性能测试等。例如,测试一个用户注册功能:

复制代码
// 用户类
public class User {
    private String username;
    private String email;
    private String password;

    public User(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }

    // Getters and setters
    public String getUsername() { return username; }
    public String getEmail() { return email; }
    public String getPassword() { return password; }
}

// 用户服务接口
public interface UserService {
    boolean registerUser(User user);
    boolean isValidEmail(String email);
}

// 用户服务实现
public class UserServiceImpl implements UserService {
    @Override
    public boolean registerUser(User user) {
        // 验证邮箱格式
        if (!isValidEmail(user.getEmail())) {
            return false;
        }
        // 验证用户名和密码长度
        if (user.getUsername().length() < 3 || user.getPassword().length() < 6) {
            return false;
        }
        // 模拟保存用户到数据库
        System.out.println("用户注册成功: " + user.getUsername());
        return true;
    }

    @Override
    public boolean isValidEmail(String email) {
        // 简单的邮箱格式验证
        return email.matches("^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$");
    }
}

// 确认测试用例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class UserServiceVerificationTest {
    @Test
    public void testRegisterUserSuccess() {
        UserService userService = new UserServiceImpl();
        User user = new User("john_doe", "[email protected]", "password123");
        assertTrue(userService.registerUser(user));
    }

    @Test
    public void testRegisterUserInvalidEmail() {
        UserService userService = new UserServiceImpl();
        User user = new User("john_doe", "invalid_email", "password123");
        assertFalse(userService.registerUser(user));
    }

    @Test
    public void testRegisterUserShortUsername() {
        UserService userService = new UserServiceImpl();
        User user = new User("jo", "[email protected]", "password123");
        assertFalse(userService.registerUser(user));
    }

    @Test
    public void testRegisterUserShortPassword() {
        UserService userService = new UserServiceImpl();
        User user = new User("john_doe", "[email protected]", "pass");
        assertFalse(userService.registerUser(user));
    }
}

12.4.4 系统测试

系统测试将软件作为一个整体进行测试,验证系统是否满足需求。例如,测试一个在线购物系统的完整流程:

复制代码
// 商品类
public class Product {
    private String productId;
    private String name;
    private double price;
    private int stock;

    public Product(String productId, String name, double price, int stock) {
        this.productId = productId;
        this.name = name;
        this.price = price;
        this.stock = stock;
    }

    // Getters and setters
    public String getProductId() { return productId; }
    public String getName() { return name; }
    public double getPrice() { return price; }
    public int getStock() { return stock; }
    public void setStock(int stock) { this.stock = stock; }
}

// 购物车类
public class ShoppingCart {
    private Map<Product, Integer> items = new HashMap<>();

    public void addItem(Product product, int quantity) {
        items.put(product, items.getOrDefault(product, 0) + quantity);
    }

    public void removeItem(Product product) {
        items.remove(product);
    }

    public double getTotalPrice() {
        double total = 0;
        for (Map.Entry<Product, Integer> entry : items.entrySet()) {
            total += entry.getKey().getPrice() * entry.getValue();
        }
        return total;
    }

    public Map<Product, Integer> getItems() {
        return items;
    }
}

// 订单类
public class Order {
    private String orderId;
    private List<Product> products;
    private double totalAmount;
    private OrderStatus status;

    public Order(String orderId, List<Product> products, double totalAmount) {
        this.orderId = orderId;
        this.products = products;
        this.totalAmount = totalAmount;
        this.status = OrderStatus.PENDING;
    }

    // Getters and setters
    public String getOrderId() { return orderId; }
    public List<Product> getProducts() { return products; }
    public double getTotalAmount() { return totalAmount; }
    public OrderStatus getStatus() { return status; }
    public void setStatus(OrderStatus status) { this.status = status; }
}

// 订单状态枚举
public enum OrderStatus {
    PENDING, PAID, SHIPPED, DELIVERED, CANCELLED
}

// 系统测试用例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class ShoppingSystemSystemTest {
    @Test
    public void testEndToEndShoppingFlow() {
        // 创建商品
        Product laptop = new Product("P001", "笔记本电脑", 5000.0, 10);
        Product mouse = new Product("P002", "鼠标", 50.0, 20);

        // 创建购物车
        ShoppingCart cart = new ShoppingCart();
        cart.addItem(laptop, 1);
        cart.addItem(mouse, 2);

        // 验证购物车总价
        assertEquals(5100.0, cart.getTotalPrice(), 0.001);

        // 创建订单
        String orderId = "ORD" + System.currentTimeMillis();
        Order order = new Order(orderId, 
                cart.getItems().keySet().stream().collect(Collectors.toList()), 
                cart.getTotalPrice());

        // 处理订单支付
        order.setStatus(OrderStatus.PAID);
        assertEquals(OrderStatus.PAID, order.getStatus());

        // 更新库存
        for (Map.Entry<Product, Integer> entry : cart.getItems().entrySet()) {
            entry.getKey().setStock(entry.getKey().getStock() - entry.getValue());
        }

        // 验证库存更新
        assertEquals(9, laptop.getStock());
        assertEquals(18, mouse.getStock());

        // 发货
        order.setStatus(OrderStatus.SHIPPED);
        assertEquals(OrderStatus.SHIPPED, order.getStatus());

        // 确认收货
        order.setStatus(OrderStatus.DELIVERED);
        assertEquals(OrderStatus.DELIVERED, order.getStatus());
    }
}

12.5 面向对象软件的测试

12.5.1 类的测试

类的测试关注类的属性、方法和状态。例如,测试一个银行账户类:

复制代码
public class BankAccount {
    private String accountNumber;
    private double balance;
    private AccountStatus status;

    public BankAccount(String accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
        this.status = AccountStatus.ACTIVE;
    }

    public void deposit(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("存款金额必须大于0");
        }
        if (status != AccountStatus.ACTIVE) {
            throw new IllegalStateException("账户状态异常,无法存款");
        }
        balance += amount;
    }

    public void withdraw(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("取款金额必须大于0");
        }
        if (status != AccountStatus.ACTIVE) {
            throw new IllegalStateException("账户状态异常,无法取款");
        }
        if (amount > balance) {
            throw new InsufficientFundsException("余额不足");
        }
        balance -= amount;
    }

    public void close() {
        if (balance != 0) {
            throw new IllegalStateException("账户余额不为0,无法关闭");
        }
        status = AccountStatus.CLOSED;
    }

    // Getters
    public String getAccountNumber() { return accountNumber; }
    public double getBalance() { return balance; }
    public AccountStatus getStatus() { return status; }
}

// 账户状态枚举
public enum AccountStatus {
    ACTIVE, CLOSED, FROZEN
}

// 自定义异常
public class InsufficientFundsException extends RuntimeException {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

// 类的测试用例
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class BankAccountTest {
    private BankAccount account;

    @BeforeEach
    public void setUp() {
        account = new BankAccount("123456", 1000.0);
    }

    @Test
    public void testInitialState() {
        assertEquals("123456", account.getAccountNumber());
        assertEquals(1000.0, account.getBalance(), 0.001);
        assertEquals(AccountStatus.ACTIVE, account.getStatus());
    }

    @Test
    public void testDeposit() {
        account.deposit(500.0);
        assertEquals(1500.0, account.getBalance(), 0.001);
    }

    @Test
    public void testDepositNegativeAmount() {
        assertThrows(IllegalArgumentException.class, () -> account.deposit(-100.0));
    }

    @Test
    public void testWithdraw() {
        account.withdraw(300.0);
        assertEquals(700.0, account.getBalance(), 0.001);
    }

    @Test
    public void testWithdrawInsufficientFunds() {
        assertThrows(InsufficientFundsException.class, () -> account.withdraw(1500.0));
    }

    @Test
    public void testCloseAccount() {
        account.withdraw(1000.0); // 清空余额
        account.close();
        assertEquals(AccountStatus.CLOSED, account.getStatus());
    }

    @Test
    public void testCloseAccountWithBalance() {
        assertThrows(IllegalStateException.class, () -> account.close());
    }
}

12.5.2 交互测试

交互测试验证对象之间的协作和交互。例如,测试一个订单处理系统中对象间的交互:

复制代码
// 订单类
public class Order {
    private String orderId;
    private List<OrderItem> items;
    private OrderStatus status;

    public Order(String orderId, List<OrderItem> items) {
        this.orderId = orderId;
        this.items = items;
        this.status = OrderStatus.PENDING;
    }

    public void processPayment(PaymentService paymentService) {
        double totalAmount = calculateTotalAmount();
        boolean paymentResult = paymentService.processPayment(totalAmount);
        if (paymentResult) {
            this.status = OrderStatus.PAID;
        }
    }

    private double calculateTotalAmount() {
        double total = 0;
        for (OrderItem item : items) {
            total += item.getProduct().getPrice() * item.getQuantity();
        }
        return total;
    }

    // Getters and setters
    public String getOrderId() { return orderId; }
    public List<OrderItem> getItems() { return items; }
    public OrderStatus getStatus() { return status; }
}

// 订单条目类
public class OrderItem {
    private Product product;
    private int quantity;

    public OrderItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }

    // Getters
    public Product getProduct() { return product; }
    public int getQuantity() { return quantity; }
}

// 商品类
public class Product {
    private String productId;
    private String name;
    private double price;

    public Product(String productId, String name, double price) {
        this.productId = productId;
        this.name = name;
        this.price = price;
    }

    // Getters
    public String getProductId() { return productId; }
    public String getName() { return name; }
    public double getPrice() { return price; }
}

// 支付服务接口
public interface PaymentService {
    boolean processPayment(double amount);
}

// 交互测试用例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

public class OrderInteractionTest {
    @Test
    public void testOrderPaymentProcess() {
        // 创建模拟的支付服务
        PaymentService paymentService = mock(PaymentService.class);
        when(paymentService.processPayment(100.0)).thenReturn(true);

        // 创建商品和订单条目
        Product product = new Product("P001", "手机", 100.0);
        OrderItem item = new OrderItem(product, 1);

        // 创建订单
        Order order = new Order("ORD123", List.of(item));

        // 处理支付
        order.processPayment(paymentService);

        // 验证结果
        assertEquals(OrderStatus.PAID, order.getStatus());
        verify(paymentService, times(1)).processPayment(100.0);
    }

    @Test
    public void testOrderPaymentFailure() {
        PaymentService paymentService = mock(PaymentService.class);
        when(paymentService.processPayment(100.0)).thenReturn(false);

        Product product = new Product("P001", "手机", 100.0);
        OrderItem item = new OrderItem(product, 1);
        Order order = new Order("ORD123", List.of(item));

        order.processPayment(paymentService);

        assertEquals(OrderStatus.PENDING, order.getStatus());
        verify(paymentService, times(1)).processPayment(100.0);
    }
}

12.5.3 继承的测试

继承的测试关注子类与父类的关系,以及多态的正确性。例如,测试一个形状继承体系:

复制代码
// 抽象形状类
public abstract class Shape {
    public abstract double calculateArea();
    public abstract double calculatePerimeter();
}

// 矩形类
public class Rectangle extends Shape {
    private double length;
    private double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    public double calculateArea() {
        return length * width;
    }

    @Override
    public double calculatePerimeter() {
        return 2 * (length + width);
    }
}

// 正方形类
public class Square extends Rectangle {
    public Square(double side) {
        super(side, side);
    }
}

// 圆形类
public class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public double calculatePerimeter() {
        return 2 * Math.PI * radius;
    }
}

// 继承测试用例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class ShapeInheritanceTest {
    @Test
    public void testRectangleArea() {
        Rectangle rectangle = new Rectangle(5.0, 3.0);
        assertEquals(15.0, rectangle.calculateArea(), 0.001);
        assertEquals(16.0, rectangle.calculatePerimeter(), 0.001);
    }

    @Test
    public void testSquareArea() {
        Square square = new Square(4.0);
        assertEquals(16.0, square.calculateArea(), 0.001);
        assertEquals(16.0, square.calculatePerimeter(), 0.001);
    }

    @Test
    public void testCircleArea() {
        Circle circle = new Circle(2.0);
        assertEquals(Math.PI * 4.0, circle.calculateArea(), 0.001);
        assertEquals(2 * Math.PI * 2.0, circle.calculatePerimeter(), 0.001);
    }

    @Test
    public void testPolymorphism() {
        Shape rectangle = new Rectangle(5.0, 3.0);
        Shape square = new Square(4.0);
        Shape circle = new Circle(2.0);

        assertEquals(15.0, rectangle.calculateArea(), 0.001);
        assertEquals(16.0, square.calculateArea(), 0.001);
        assertEquals(Math.PI * 4.0, circle.calculateArea(), 0.001);
    }
}

12.6小结

软件测试是软件开发过程中不可或缺的环节,它贯穿于整个软件生命周期。通过本章的学习,我们了解了软件测试的概念、过程模型、测试方法以及面向对象软件的测试技术。合理运用各种测试方法和技术,能够有效发现软件中的缺陷,提高软件质量,确保软件满足用户需求。在实际项目中,应根据项目特点和需求,选择合适的测试策略和方法,制定全面的测试计划,以保证软件的可靠性和稳定性。

相关推荐
liuyang-neu31 分钟前
黑马点评双拦截器和Threadlocal实现原理
java
csdn_aspnet1 小时前
Java 程序求圆弧段的面积(Program to find area of a Circular Segment)
java·开发语言
Magnum Lehar3 小时前
vulkan游戏引擎vulkan部分的fence实现
java·前端·游戏引擎
on the way 1233 小时前
创建型模式之Factory Method(工厂方法)
android·java·工厂方法模式
无心水3 小时前
【后端高阶面经:MongoDB篇】41、MongoDB 是怎么做到高可用的?
java·开发语言·mongodb·java面试·高可用·后端高阶面经·后端工程师的高阶面经
无心水3 小时前
【后端高阶面经:MongoDB篇】40、怎么优化MongoDB的查询性能?
java·开发语言·mongodb·java面试·后端高阶面经·后端工程师的高阶面经·java高阶面经
gb42152873 小时前
更新时间相差8个小时
java·开发语言
麻花20133 小时前
获取oracle的HQL日志,采取参数日志,拼装SQL语句
java·oracle
代码老y3 小时前
基于springboot的校园商铺管理系统的设计与实现
java·vue.js·spring boot·后端·毕业设计·课程设计·个人开发
橙子199110163 小时前
说说 Kotlin 中的 Any 与 Java 中的 Object 有何异同?
java·开发语言·kotlin