SpringBoot整合Retry详细教程

问题背景

在现代的分布式系统中,服务间的调用往往需要处理各种网络异常、超时等问题。重试机制是一种常见的解决策略,它允许应用程序在网络故障或临时性错误后自动重新尝试失败的操作。Spring Boot 提供了灵活的方式来集成重试机制,这可以通过使用 Spring Retry 模块来实现。本文将通过一个具体的使用场景来详细介绍如何在 Spring Boot 应用中集成和使用 Spring Retry 技术。

场景描述

假如我们正在开发一个OMS系统(订单管理系统),其中一个关键服务 OrderService 负责订单创建和调用WMS服务扣减库存API 。由于网络不稳定或外部 API 可能暂时不可用,我们需要在这些情况下实现重试机制,以确保请求的成功率和系统的稳定性。

实现步骤

1. 添加依赖

首先,在你的 pom.xml 文件中添加 Spring RetryAOP 的依赖:

<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Retry --><dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency><!-- Spring Boot Starter AOP --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies>

2. 创建配置类

创建一个配置类来配置重试模板:

package com.zlp.retry.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
/***  全局重试配置*/
@Configuration
public class CustomRetryConfig {/**** 这段代码定义了一个 `CustomRetryConfig` 类,其中包含一个 `retryTemplate` 方法。该方法用于创建并配置一个 `RetryTemplate` 对象,该对象用于处理重试逻辑。** 1. 创建 `RetryTemplate` 实例**:创建一个 `RetryTemplate` 对象。* 2. 设置重试策略:使用 `SimpleRetryPolicy` 设置最大重试次数为5次。* 3. 设置延迟策略:使用 `ExponentialBackOffPolicy` 设置初始延迟时间为1000毫秒,每次重试间隔时间乘以2。* 4. 应用策略:将重试策略和延迟策略应用到 `RetryTemplate` 对象。*/@Beanpublic RetryTemplate retryTemplate() {RetryTemplate template = new RetryTemplate();// 设置重试策略SimpleRetryPolicy policy = new SimpleRetryPolicy();policy.setMaxAttempts(5);// 设置延迟策略ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();backOffPolicy.setInitialInterval(1000);backOffPolicy.setMultiplier(2.0);template.setRetryPolicy(policy);template.setBackOffPolicy(backOffPolicy);return template;}
}

3. 创建服务类

创建一个服务类 OrderService和接口实现类OrderServiceImpl,并在需要重试的方法上使用 @Retryable 注解:

/*** @Classname OrderService* @Date 2024/11/18 21:03* @Created by ZouLiPing*/
public interface OrderService {/*** 创建订单* @param createOrderReq* @return*/String createOrder(CreateOrderReq createOrderReq);
}
package com.zlp.retry.service.impl;import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.zlp.retry.dto.CreateOrderReq;
import com.zlp.retry.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;import java.util.UUID;/*** @Classname OrderServiceImpl* @Date 2024/11/18 21:06* @Created by ZouLiPing*/
@Service
@Slf4j(topic = "OrderServiceImpl")
public class OrderServiceImpl implements OrderService {@Override@Retryable(value = {Exception.class},maxAttempts = 4, backoff = @Backoff(delay = 3000))public String createOrder(CreateOrderReq createOrderReq) {log.info("createOrder.req createOrderReq:{}", JSON.toJSONString(createOrderReq));try {log.info("createOrder.deductStock.调用时间={}", DateUtil.formatDateTime(DateUtil.date()));// 扣减库存服务this.deductStock(createOrderReq);} catch (Exception e) {throw new RuntimeException(e);}return UUID.randomUUID().toString();}/*** 模拟扣减库存*/private void deductStock(CreateOrderReq createOrderReq) {throw new RuntimeException("库存扣减失败");}/*** 当重试四次仍未能成功创建订单时调用此方法进行最终处理** @param ex 异常对象,包含重试失败的原因* @param createOrderReq 创建订单的请求对象,包含订单相关信息* @return 返回处理结果,此处返回"fail"表示最终失败*/@Recoverpublic String recover(Exception ex, CreateOrderReq createOrderReq) {// 记录重试四次后仍失败的日志,包括异常信息和订单请求内容log.error("recover.resp.重试四次还是失败.error:{},createOrderReq:{}",ex.getMessage(),JSON.toJSONString(createOrderReq));// 处理最终失败的情况// 可以记录日志,或者是投递MQ,采用最终一致性的方式处理return "fail";}
}

4. 启用重试功能

在主配置类或启动类上添加 @EnableRetry 注解,以启用重试功能:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;@SpringBootApplication
@EnableRetry
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

5. 验证重试方法


@RestController
@RequiredArgsConstructor
public class RetryController {private final OrderService orderService;@GetMapping("getRetry")public String retry(){CreateOrderReq createOrderReq = new CreateOrderReq();createOrderReq.setOrderId(UUID.randomUUID().toString());createOrderReq.setProductId("SKU001");createOrderReq.setCount(10);createOrderReq.setMoney(100);return orderService.createOrder(createOrderReq);}
}

6.执行操作说明

  1. 添加依赖:引入了 Spring Retry 和 AOP 的依赖,以便使用重试功能。
  2. 配置重试模板:创建了一个配置类 CustomRetryConfig,配置了重试策略,设置最大重试次数为5次。
  3. 创建服务类:在 OrderServiceImpl 类中,使用 @Retryable 注解标记了 createOrder 方法,指定了当发生 Exception 时进行重试,最大重试次数为4次,每次重试间隔3秒。同时,使用 @Recover 注解标记了 recover 方法,当所有重试都失败后,会调用这个方法
  4. 启用重试功能:在主配置类或启动类上添加 @EnableRetry 注解,以启用重试功能。

Retry执行流程
Retry整体流程图

开始操作
操作成功?
结束
等待延迟
递增重试计数
达到最大重试次数?
抛出异常
重试操作

打印日志

从日志分析每隔3秒钟会重试一次,直到到达设置最大重试次数,会调用功<font style="color:#DF2A3F;">recover</font>方法中

7.结论

通过以上步骤,我们成功地在 Spring Boot应用中集成了 Spring Retry 技术,实现了服务调用的重试机制。这不仅提高了系统的健壮性和稳定性,还减少了因网络问题或外部服务暂时不可用导致的请求失败。希望本文对你理解和应用 Spring Boot 中的重试技术有所帮助。


Retry配置的优先级规则

  1. 方法级别配置:如果某个配置在方法上定义了,则该方法上的配置会覆盖类级别的配置和全局配置。
  2. 类级别配置:如果某个配置在类上定义了,并且该类的方法没有单独定义配置,则使用类级别的配置。
  3. 全局配置:如果没有在方法或类上定义配置,则使用全局配置。

下面通过一个具体的例子来展示这些优先级规则。假设我们有一个服务类 <font style="color:rgb(44, 44, 54);">MyService</font>,其中包含一些方法,并且我们在不同的层次上进行了重试策略的配置。

示例代码

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;@Service
@Retryable(value = {RuntimeException.class},maxAttempts = 3,backoff = @Backoff(delay = 1000) // 类级别的配置
)
public class MyService {@Retryable(value = {RuntimeException.class},maxAttempts = 5,backoff = @Backoff(delay = 500) // 方法级别的配置)public void retryableMethodWithSpecificConfig() {System.out.println("Retrying with specific config...");throw new RuntimeException("Simulated exception");}@Retryable(value = {RuntimeException.class})public void retryableMethodWithoutSpecificDelay() {System.out.println("Retrying without specific delay...");throw new RuntimeException("Simulated exception");}public void nonRetryableMethod() {System.out.println("This method does not retry.");throw new RuntimeException("Simulated exception");}
}

解释

  1. retryableMethodWithSpecificConfig
    • 方法级别配置
      • <font style="color:rgb(44, 44, 54);">maxAttempts = 5</font>
      • <font style="color:rgb(44, 44, 54);">backoff.delay = 500</font>
    • 这些配置会覆盖类级别的配置。
  2. retryableMethodWithoutSpecificDelay
    • 方法级别配置
      • <font style="color:rgb(44, 44, 54);">maxAttempts = 3</font> (继承自类级别)
      • <font style="color:rgb(44, 44, 54);">backoff.delay = 1000</font> (继承自类级别)
    • 这些配置继承自类级别的配置。
  3. nonRetryableMethod
    • 该方法没有使用 <font style="color:rgb(44, 44, 54);">@Retryable</font> 注解,因此不会进行重试。

全局配置示例

为了进一步说明全局配置的优先级,我们可以配置一个全局的重试模板。

配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;@Configuration
public class RetryConfig {@Beanpublic RetryTemplate retryTemplate() {RetryTemplate template = new RetryTemplate();SimpleRetryPolicy policy = new SimpleRetryPolicy();policy.setMaxAttempts(4);template.setRetryPolicy(policy);FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();fixedBackOffPolicy.setBackOffPeriod(750L);template.setBackOffPolicy(fixedBackOffPolicy);return template;}
}
使用全局配置的服务类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;@Service
public class AnotherService {@Autowiredprivate RetryTemplate retryTemplate;@Retryable(value = {RuntimeException.class},maxAttempts = 6, // 方法级别的配置backoff = @Backoff(delay = 300) // 方法级别的配置)public void retryableMethodWithGlobalAndLocalConfig() {System.out.println("Retrying with global and local config...");throw new RuntimeException("Simulated exception");}@Retryable(value = {RuntimeException.class})public void retryableMethodWithOnlyGlobalConfig() {System.out.println("Retrying with only global config...");throw new RuntimeException("Simulated exception");}
}

解释

  1. retryableMethodWithGlobalAndLocalConfig
    • 方法级别配置
      • <font style="color:rgb(44, 44, 54);">maxAttempts = 6</font>
      • <font style="color:rgb(44, 44, 54);">backoff.delay = 300</font>
    • 这些配置会覆盖全局配置。
  2. retryableMethodWithOnlyGlobalConfig
    • 全局配置
      • <font style="color:rgb(44, 44, 54);">maxAttempts = 4</font>
      • <font style="color:rgb(44, 44, 54);">backoff.delay = 750</font>
    • 这些配置继承自全局配置。

总结一下,配置的优先级从高到低依次是:

  1. 方法级别配置
  2. 类级别配置
  3. 全局配置

希望这个示例能帮助你理解不同层次配置的优先级。

什么样的场景不适合Retry

在使用重试机制时,确实有一些场景不适合应用重试策略。了解这些场景有助于避免不必要的重试操作,从而提高系统的性能和稳定性。以下是几种不适合使用重试机制的常见场景:

  1. 幂等性不可保证的操作
    • 解释:如果一个操作不是幂等的(即多次执行会产生不同的结果),那么重试可能导致数据不一致或其他问题。
    • 示例:插入数据库记录的操作通常不是幂等的,因为重复插入会导致重复的数据。
  2. 长时间运行的操作
    • 解释:对于耗时较长的操作,频繁重试可能会导致系统资源被大量占用,影响其他任务的执行。
    • 示例:批量处理大数据集、长时间计算的任务。
  3. 外部依赖不稳定但无法恢复
    • 解释:某些外部服务或API可能存在根本性的故障,无法通过简单的重试解决。在这种情况下,重试只会浪费资源。
    • 示例:调用第三方支付接口,如果返回的是明确的失败状态码(如账户余额不足),则不应该重试。
  4. 网络超时且无可用备用路径
    • 解释:在网络请求超时时,如果没有任何备用路径或解决方案,重试可能仍然会失败。
    • 示例:尝试连接到某个特定IP地址的服务,如果该地址一直不通,则重试没有意义。
  5. 用户交互过程中需要立即反馈的操作
    • 解释:在用户等待响应的过程中,长时间的重试可能导致用户体验不佳。
    • 示例:提交表单后立即显示成功消息,如果在此期间发生错误并进行重试,用户可能会感到困惑。
  6. 涉及敏感信息的操作
    • 解释:对于涉及敏感信息的操作(如密码修改、资金转账),重试可能会导致敏感信息泄露或重复操作。
    • 示例:更新用户的银行账户信息,一旦确认操作完成,不应再进行重试。
  7. 事务边界内的操作
    • 解释:在事务边界内,重试可能会导致事务冲突或回滚,增加复杂性。
    • 示例:在一个复杂的数据库事务中,部分操作失败后进行重试可能导致整个事务失败。
  8. 已知的永久性错误
    • 解释:如果能够明确判断出错误是永久性的(如配置错误、代码bug),重试不会解决问题。
    • 示例:尝试读取不存在的文件,这种错误通常是永久性的。
  9. 高并发环境下的写操作
    • 解释:在高并发环境下,频繁的重试可能会加剧数据库负载,导致更多的锁竞争和死锁。
    • 示例:在电商网站的下单高峰期,对库存的减少操作不宜频繁重试。

示例代码

为了更好地理解这些原则,下面是一个简单的示例,展示了如何在Spring Boot中使用<font style="color:rgb(44, 44, 54);">@Retryable</font>注解,并根据上述原则决定哪些操作适合重试。


import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;@Service
public class MyService {// 适合重试的操作:幂等性强、短时间操作、可恢复的错误@Retryable(value = {RuntimeException.class},maxAttempts = 3,backoff = @Backoff(delay = 1000))public void retryableFetchData() {System.out.println("Fetching data...");// 模拟网络请求或短暂的外部服务调用if (Math.random() > 0.5) {throw new RuntimeException("Simulated transient network error");}}// 不适合重试的操作:幂等性不可保证、长时间运行public void nonRetryableLongRunningTask() {System.out.println("Starting long-running task...");try {Thread.sleep(10000); // 模拟长时间运行的任务} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Long-running task completed.");}// 不适合重试的操作:涉及敏感信息public void updateSensitiveInformation(String sensitiveData) {System.out.println("Updating sensitive information...");// 这里假设更新操作不是幂等的,也不应该重试throw new RuntimeException("Simulated failure in updating sensitive information");}// 不适合重试的操作:已知的永久性错误public void fetchDataFromNonExistentResource() {System.out.println("Fetching data from a non-existent resource...");throw new RuntimeException("Permanent error: Resource not found");}
}

解释

  1. retryableFetchData
    • 适用条件
      • 幂等性强:每次请求的结果相同。
      • 短时间操作:模拟网络请求或短暂的外部服务调用。
      • 可恢复的错误:模拟暂时的网络错误。
    • 重试策略
      • 最大重试次数为3次。
      • 每次重试间隔1秒。
  2. nonRetryableLongRunningTask
    • 不适用原因
      • 长时间运行:模拟长时间运行的任务。
      • 重试可能导致资源过度消耗。
  3. updateSensitiveInformation
    • 不适用原因
      • 涉及敏感信息:更新操作不是幂等的,也不应该重试。
      • 重试可能导致数据不一致或其他安全问题。
  4. fetchDataFromNonExistentResource
    • 不适用原因
      • 已知的永久性错误:资源不存在,重试不会解决问题。

通过这些示例,你可以更好地理解哪些操作适合重试以及为什么某些操作不适合重试。

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

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

相关文章

爬取boss直聘上海市人工智能招聘信息+LDA主题建模

爬取boss直聘上海市人工智能招聘信息 import time import tqdm import random import requests import json import pandas as pd import os from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriv…

项目快过:知识蒸馏 | 目标检测 |FGD | Focal and Global Knowledge Distillation for Detectors

公开时间&#xff1a;2022年3月9号 项目地址&#xff1a;https://github.com/yzd-v/FGD 论文地址&#xff1a;https://arxiv.org/pdf/2111.11837 知识蒸馏已成功地应用于图像分类。然而&#xff0c;目标检测要复杂得多&#xff0c;大多数知识蒸馏方法都失败了。本文指出&#…

【Linux】匿名管道通信场景——进程池

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…

Sybase数据恢复—Sybase数据库无法启动,Sybase Central连接报错的处理案例

Sybase数据库数据恢复环境&#xff1a; Sybase数据库版本&#xff1a;SQL Anywhere 8.0。 Sybase数据库故障&分析&#xff1a; Sybase数据库无法启动。 错误提示&#xff1a; 使用Sybase Central连接报错。 数据库数据恢复工程师经过检测&#xff0c;发现Sybase数据库出现…

分布式FastDFS存储的同步方式

目录 一&#xff1a;FatsDFS的结构图 二&#xff1a;FatsDFS文件同步 前言&#xff1a; 1&#xff1a;同步日志所在目录 2&#xff1a;binlog格式 3&#xff1a;同步规则 4&#xff1a;binlog同步过程 1 &#xff1a;获取组内的其他Storage信息 tracker_report_thread_e…

【绘图】数据可视化(python)

对于数据绝对值差异较大&#xff08;数据离散&#xff09; 1. 对数坐标直方图&#xff08;Histogram with Log Scale&#xff09; import pandas as pd import matplotlib.pyplot as plt import numpy as np# 示例数据 data {count: [10, 20, 55, 90, 15, 5, 45, 80, 1000, …

使用Dify与BGE-M3搭建RAG(检索增强生成)应用-改进一,使用工作流代替Agnet

文章目录 前言Agent vs 工作流编写工作流 前言 在上一篇中&#xff0c;我们实现了一个基本的基于Dify的RAG的示范。 使用Dify与BGE-M3搭建RAG&#xff08;检索增强生成&#xff09;应用 这个效果确实很差。 我们一起来看看&#xff0c;该怎么改进。 今天我们就尝试一下&…

【Linux课程学习】:文件第二弹---理解一切皆文件,缓存区

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 Linux学习笔记&#xff1a; https://blog.csdn.net/d…

【iOS】《Effective Objective-C 2.0》阅读笔记(一)

文章目录 前言了解OC语言的起源在类的头文件中尽量少引入其他头文件多用字面量语法&#xff0c;少用与之等价的方法字面量数值字面量数组字面量字典 多用类型常量&#xff0c;少用#define预处理指令用枚举法表示状态、选项、状态码 总结 前言 最近开始阅读一些iOS开发的相关书籍…

猫狗分类调试过程

一&#xff0c;下载名称为archive数据集 下载方式&#xff1a;机房共享文件夹 二、打开CatDogProject项目 配置环境&#xff1a;选择你所建的环境 三、调试运行 1&#xff0c;报错一&#xff1a;Traceback (most recent call last): File "G:/AI_Project/CatDogPro…

探索Python WebSocket新境界:picows库揭秘

文章目录 探索Python WebSocket新境界&#xff1a;picows库揭秘第一部分&#xff1a;背景介绍第二部分&#xff1a;picows库概述第三部分&#xff1a;安装picows库第四部分&#xff1a;简单库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方案第…

零基础学安全--Burp Suite(4)proxy模块以及漏洞测试理论

目录 学习连接 一些思路 proxy模块 所在位置 功能简介 使用例子 抓包有一个很重要的点&#xff0c;就是我们可以看到一些在浏览器中看不到的传参点&#xff0c;传参点越多就意味着攻击面越广 学习连接 声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可…

30 基于51单片机的手环设计仿真

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;DHT11温湿度采集温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器模拟水位传感器检测水位&#xff0c;通过LCD1602显示信息&#xff0c;然后在程序里设置好是否…

十一、快速入门go语言之接口和反射

文章目录 接口:one: 接口基础:two: 接口类型断言和空接口:star2: 空接口实现存储不同数据类型的切片/数组:star2: 复制切片到空接口切片:star2: 类型断言 反射 &#x1f4c5; 2024年5月9日 &#x1f4e6; 使用版本为1.21.5 接口 十、Java类的封装和继承、多态 - 七点半的菜市…

QT6学习第六天 初识QML

QT6学习第六天 创建Qt Quick UI项目使用Qt Quick DesignerQML 语法基础导入语句 import对象 object 和属性 property布局注释表达式和属性绑定QML 编码约定 设置应用程序图标 创建Qt Quick UI项目 如果你有只测试QML相关内容快速显示界面的需求&#xff0c;这时可以创建Qt Qui…

图解RabbitMQ七种工作模式生产者消费者模型的补充

文章目录 1.消费者模型2.生产者-消费者模型注意事项2.1资源释放顺序问题2.2消费者的声明问题2.3虚拟机和用户的权限问题 3.七种工作模式3.1简单模式3.2工作模式3.3发布/订阅模式3.4路由模式3.5通配符模式3.6RPC通信3.7发布确认 1.消费者模型 之前学习的这个消息队列的快速上手…

C-操作符

操作符种类 在C语言中&#xff0c;操作符有以下几种&#xff1a; 算术操作符 移位操作符 位操作符 逻辑操作符 条件操作符 逗号表达式 下标引用&#xff0c;函数调用 拓展&#xff1a;整型提升 我们介绍常用的几个 算术操作符 &#xff08;加&#xff09;&#xff…

使用 Spring Boot 和 GraalVM 的原生镜像

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;历代文学&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编程&#xff0c;高并发设计&#xf…

基于Java Springboot宠物医院微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 微信…

Tree搜索二叉树、map和set_数据结构

数据结构专栏 如烟花般绚烂却又稍纵即逝的个人主页 本章讲述数据结构中搜索二叉树与HashMap的学习&#xff0c;感谢大家的支持&#xff01;欢迎大家踊跃评论&#xff0c;感谢大佬们的支持! 目录 搜索二叉树的概念二叉树搜索模拟实现搜索二叉树查找搜索二叉树插入搜索二叉树删除…