10 Redis之SB整合Redis

7. SB整合Redis

Spring Boot 中可以直接使用 Jedis 实现对 Redis 的操作,但一般不这样用,而是使用 Redis操作模板 RedisTemplate 类的实例来操作 Redis。

RedisTemplate 类是一个对 Redis 进行操作的模板类。该模板类中具有很多方法,这些方法很多与 Redis 操作命令同名或类似。例如,delete()、keys()、scan(),还有事务相关的 multi()、exec()、discard()、watch()等。当然还有获取对各种 Value 类型进行操作的操作实例的两类方法 boundXxxOps(k)与 opsForXxx()。

7.1 需求

对于一个资深成熟的金融产品交易平台,其用户端首页一般会展示其最新金融产品列表,同时还为用户提供了产品查询功能。
另外,为了显示平台的实力与信誉,在平台首页非常显眼的位置还会展示平台已完成的总交易额与注册用户数量。

对于管理端,管理员可通过管理页面修改产品、上架新产品、下架老产品。

为了方便了解 Redis 与 Spring Boot 的整合流程,这里对系统进行了简化:用户端首页仅提供根据金融产品名称的查询,显眼位置仅展示交易总额。
管理端仅实现上架新产品功能。

7.2 准备

  1. 创建一个SB工程 , JDK8, SB版本2.7.4
  2. 导入依赖
  3. resource下创建一个文件夹webapp
  4. 创建一张product表
  5. 编写yaml文件
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.sunsplanter</groupId>
    <artifactId>SB-Redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SB-Redis</name>
    <description>SB-Redis</description>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>
        <dependency>
            www.bjpowernode.com 187 / 248 Copyright© 动力节点
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(20) DEFAULT NULL,
 `rate` double DEFAULT NULL,
 `amount` double DEFAULT NULL,
 `raised` double DEFAULT NULL,
 `cycle` int(11) DEFAULT NULL,
 `endTime` char(10) DEFAULT '0',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
www.bjpowernode.com 190 / 248 Copyright© 动力节点
INSERT INTO `product` VALUES (1,'天鑫添益 2',2.76,50000,20000,30,'2022-07-10'),(2,'国
泰添益',2.86,30000,30000,60,'2022-07-12'),(3,'国泰高鑫
',2.55,60000,50000,90,'2022-07-09'),(4,'国福民安
',2.96,30000,20000,7,'2022-05-10'),(5,'天益鑫多
',2.65,80000,60000,20,'2022-07-05'),(6,'惠农收益
',3.05,30000,20000,10,'2022-06-10'),(7,'惠农三鑫
',2.76,50000,30000,30,'2022-07-02'),(8,'励学收益',2.86,30000,20000,20,'2022-07-11');
mybatis:
  mapper-locations: classpath:com/sunsplanter/dao/*.xml
  type-aliases-package: com.sunsplanter.bean

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/tanhua?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT
    username: root
    password: ???
    driver-class-name: com.mysql.cj.jdbc.Driver

Logging:
  pattern:
    console: level-%-5level - %msg%n

7.3 编写代码

在这里插入图片描述

7.3.1 controller

package com.sunsplanter.controller;

@Controller
public class ProductController {

    @Autowired
    private ProductService service;

    @GetMapping("/")
    public String indexHandle(Model model) {// 查询总交易额
        Double turnover = service.findTurnover();
        model.addAttribute("turnover", turnover);

        //查询所有产品
        List<Product> allProducts = service.findAllProducts();
        model.addAttribute("allProducts", allProducts);
        return "/index.jsp";
    }

    // 上架新产品,然后返回管理页面
    @PostMapping("/product/")
    public String registerHandle(Product product, Model model) {
        //添加新产品
        service.saveProduct(product);

        // 查询所有产品
        List<Product> allProducts = service.findAllProducts();
        model.addAttribute("allProducts", allProducts);
        return "/jsp/manager.jsp";
    }

    // 根据产品名称查询产品
    @GetMapping("/product/name")
    public String listHandle(String name, Model model) {
        List<Product> result = service.findProductsByName(name);
        model.addAttribute("result", result);
        model.addAttribute("name", name);
        return "/jsp/result.jsp";
    }
}

7.3.2 service

package com.sunsplanter.service;

public interface ProductService {
    void saveProduct(Product product);

    List<Product> findAllProducts();

    Double findTurnover();

    List<Product> findProductsByName(String name);
}




package com.sunsplanter.service.impl;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductDao dao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProduct(Product product) {
        dao.insertProduct(product);

    }

    @Override
    public List<Product> findProductsByName(String name) {
        return dao.selectProductsByName(name);
    }

    @Override
    public List<Product> findAllProducts() {
        return dao.selectAllProducts();
    }

    @Override
    public Double findTurnover() {
        //获取当前日期并格式化
        Date date =new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        //从DB中查询turnover
        Object turnover = dao.selectTurnover(sdf.format(date));
        return (Double) turnover;
    }
}

7.3.3 bean

package com.sunsplanter.bean;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    private Integer id;

    private String name;

    //年华利率
    private Double rate;

    //募集总额
    private Double amount;

    //已募集金额
    private Double raised;

    //产品募集结束时间
    private Integer cycle;

    private String endtime;
}

7.3.4 dao接口和mapper.xml

package com.sunsplanter.dao;

@Mapper
public interface ProductDao {
    void insertProduct(Product product);

    List<Product> selectAllProducts();

    List<Product> selectProductsByName(String name);

    Object selectTurnover(String date);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sunsplanter.dao.ProductDao">

    <insert id="insertProduct">
        insert into product(name, rate, amount, raised, cycle, endTime)
        values (#{name}, #{rate}, #{amount}, #{raised}, #{cycle}, #{endTime})
    </insert>

    <select id="selectAllProducts" resultType="Product">
        select id,name,rate, amount,raised, cycle,endTime
        from product
    </select>

    <select id="selectProductsByName" resultType="Product">
        select id,name,rate,amount,raised, cycle,endTime
        from product
        where name like '%'#{xxx}'%'
    </select>

    <select id="selectTurnover" resultType="double">
        select sum(raised)
        from product
        where endTime is not null and endTime &lt; #{xxx}
</select>

</mapper>

7.4 测试与问题

以上是一个纯SpringBoot项目, 并未整合任何Redis.以下示例

7.5 整合Redis

Spring Boot 与 Redis 整合 大体上为以下几步

  1. 在 POM 中导入依赖
  2. 在配置文件中注册 Redis 连接信息与缓存信息
  3. 需要缓存到 Redis 中的实体类必须要序列化
  4. Spring Boot 启动类中要添加@EnableCaching 注解
  5. 查询方法上要添加@Cacheable 注解
  6. 对数据进行写操作的方法上添加@CacheEvict 注解
  7. 对于需要手工操作 Redis 的方法,需通过 RedisTemplate 来获取操作对象

7.5.0 学习SB中的Redis操作

7.5.0.1 @Cacheable

@Cacheable可以标记在一个方法上,也可以标记在一个类上。
当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。

对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。

Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。

	常用的属性
    cacheNames/value :用来指定缓存组件的名字

    key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写)
    
    condition :可以用来指定符合条件的情况下才缓存

    keyGenerator :key 的生成器。 key 和 keyGenerator 二选一使用

    cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。

    unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)

    sync :是否使用异步模式。
  1. value属性指定Cache名称

    value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。

   @Cacheable("cache1")//Cache是发生在cache1上的
   public User find(Integer id) {
      return null;
   }
  1. key属性自定义key

    该属性支持SpringEL表达式。
    当我们没有指定该属性时,Spring将使用默认策略生成key。
    

我们这里先来看看自定义策略,至于默认策略会在后文单独介绍。
自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。下面是几个使用参数作为key的示例。

   @Cacheable(value="users", key="#id")
   public User find(Integer id) {

      returnnull;

   }

 

   @Cacheable(value="users", key="#p0")
   public User find(Integer id) {

      returnnull;

   }

 

   @Cacheable(value="users", key="#user.id")
   public User find(User user) {

      returnnull;

   }

 

   @Cacheable(value="users", key="#p0.id")
   public User find(User user) {

      returnnull;

   }

除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。

在这里插入图片描述

   当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。如:
   @Cacheable(value={"users", "xxx"}, key="caches[1].name")
   public User find(User user) {

      returnnull;

   }
  1. condition属性指定发生的条件
    有的时候我们可能并不希望缓存一个方法所有的返回结果。通过condition属性可以实现这一功能。
    condition属性默认为空,表示将缓存所有的调用情形。
    其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下示例表示只有当user的id为偶数时才会进行缓存。
 @Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
   public User find(User user) {

      System.out.println("find user by user " + user);

      return user;

   }
7.5.0.2 @CacheEvict
   @CacheEvict是用来标注在需要清除缓存元素的方法或类上的。
   当标记在一个类上时表示其中所有的方法的**执行后**都会触发缓存的清除操作。
   @CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。
   其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。
  1. allEntries属性

    allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。
    当指定了allEntries为true时,Spring Cache将删除所有除了指定的key以外的所有key。
    有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。

   @CacheEvict(value="users", allEntries=true)
   public void delete(Integer id) {

      System.out.println("delete user by id: " + id);

   }
  1. beforeInvocation属性

    清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。
    使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

   @CacheEvict(value="users", beforeInvocation=true)
   public void delete(Integer id) {

      System.out.println("delete user by id: " + id);

   }

7.5.0.3 RedisTemplate常用集合

RedisTemplate常用集合

7.5.1 准备

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
redis:
	host:redis
	port:6379

#Sentinel高可用集群
#sentinel:
#  master: mymaster
#  nodes: redis:26380,redis:26381,redis:26382

#Cluster分布式系统
#cluster:
#  nodes: redis:6380,redis:6381,edis:6382,edis:6383,redis:6384,redis:6385
	
cache:
	type: redis
	cache-names: pc

7.5.2 修改实体类

由于要将查询的实体类对象缓存到 Redis,Redis 要求实体类必须序列化。所以需要实体类实现序列化接口。

class Product implements Serializable {

7.5.3 修改serviceImpl类

//注入RedisTemplate模板
@Autowired
private RedisTemplate<0bject,0bject> rt;
//清除名为pc的缓存空间. 且清除其内的所有条目,如果想要保留一些, 则需通过 key 属性指定要清理的 key 数据。
//该注解会在方法体执行前执行
@0verride
@Transactional(rollbackFor=Exception.class)
@CacheEvict(value ="pc",allEntries = true)
public void saveProduct(Product product){
	dao.insertProduct(product);
}


@Override
public Double findTurnover(){

	//绑定键为"turnover的键值对, 然后就可以对其进行操作"
	BoundValue0perations<Object, 0bject> ops = rt.boundValue0ps("turnover");
	Object turnover = ops.get();
	
	//先从缓存中查, 如果缓存中没有, 再从DB中获取, 最终写入缓存
	if(turnover == null){
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd")
		
		turnover = dao.selectTurnover(sdf.format(date));
		//写入缓存
		ops.set(turnover,10,TimeUnit.SECONDS);
	}
	return (Double) turnover;
}

7.5.4 启动类增加注解

@EnableCaching 用于开启当前应用的缓存功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

stable-diffusion-webui+sadTalker开启GFPGAN as Face enhancer

接上一篇&#xff1a;在autodl搭建stable-diffusion-webuisadTalker-CSDN博客 要开启sadTalker gfpgan as face enhancer&#xff0c; 需要将 1. stable-diffusion-webui/extensions/SadTalker/gfpgan/weights 目录下的文件拷贝到 :~/autodl-tmp/models/GFPGAN/目录下 2.将G…

杰理-按键多次按下识别多击

杰理-按键多次按下识别多击 #define ALL_KEY_EVENT_CLICK_ONLY 0 //是否全部按键只响应单击事件

ansys计算结果保存

100 &#xff1a; 图片质量 ON&#xff1a;白色背景 右键设置保存图片的背景格式&#xff1a;

基于Python网络爬虫的IT招聘就业岗位数据分析可视化推荐系统

文章目录 基于Python网络爬虫的IT招聘就业岗位数据分析可视化推荐系统项目概述招聘岗位数据爬虫分析系统展示用户注册登录系统首页IT招聘数据开发岗-javaIT招聘数据开发岗-PythonIT招聘数据开发岗-AndroidIT招聘数据开发岗-其它招聘岗位数据分析算法方面运维方面测试方面招聘岗…

redis是单线程,为什么这么快?

redis是纯内存操作&#xff0c;C语言编写&#xff0c;执行速度非常快。 采用单线程&#xff0c;避免不必要的上下文切换&#xff0c;不用考虑线程安全问题。 采用I/O多路复用模型&#xff0c;非阻塞I/O。 例如&#xff1a;bgsave和bgrewriteaof都是在后台执行操作&#xff0…

农业四情监测设备为什么符合高标准农田建设

TH-Q3随着科技的不断进步&#xff0c;智慧农业正逐渐成为现代农业发展的重要方向。其中&#xff0c;农业四情监测系统以其独特的功能和优势&#xff0c;在高标准农田建设中发挥着越来越重要的作用。 一、农业四情监测系统的概念及功能 农业四情监测系统&#xff0c;顾名思义&am…

C++之queue和dqueue

1、queue queue&#xff08;队列&#xff09;&#xff0c;一种数据结构&#xff0c;可以让某些数据结构的操作变得简单。队列&#xff08;queue&#xff09;最大的特点就是先进先出。就是说先放入queue容器的元素一定是要先出队列之后&#xff0c;比它后进入队列的元素才能够出…

算法沉淀——动态规划之回文串问题(上)(leetcode真题剖析)

算法沉淀——动态规划之回文串问题 01.回文子串02.最长回文子串03.分割回文串 IV04.分割回文串 II05.最长回文子序列06.让字符串成为回文串的最少插入次数 01.回文子串 题目链接&#xff1a;https://leetcode.cn/problems/palindromic-substrings/ 给你一个字符串 s &#xf…

08 MyBatis之查询专题(返回对象/Map/List封装Map/Map封装Map)+列名与属性名映射的三种方法

准备: INSERT INTO t_car (id, car_num, brand, guide_price, produce_time, car_type) VALUES (165, 6666, 丰田霸道, 32.00, 2020-11-11, 燃油车); INSERT INTO t_car (id, car_num, brand, guide_price, produce_time, car_type) VALUES (166, 1202, 大众速腾, 30.00, 2020…

IntelliJ IDEA 2023:创新不止步,开发更自由 mac/win版

IntelliJ IDEA 2023激活版是一款强大而智能的集成开发环境(IDE)&#xff0c;为开发者提供了一系列先进的功能和工具&#xff0c;帮助他们更高效地编写、调试和测试代码。 IntelliJ IDEA 2023 软件获取 IntelliJ IDEA 2023继承了其前代版本的优秀基因&#xff0c;并在此基础上进…

基于AMDGPU-ROCm的深度学习环境搭建

在风起云涌的AI江湖&#xff0c;NVIDIA凭借其CUDA生态和优秀的硬件大杀四方&#xff0c;立下赫赫战功&#xff0c;而另一家公司AMD也不甘示弱&#xff0c;带着他的生态解决方案ROCm开始了与不世出的NVIDA的正面硬钢&#xff0c;"ROCm is the answer to CUDA", AMD官网…

177基于matlab的基于S函数的变步长自适应滤波算法

基于matlab的基于S函数的变步长自适应滤波算法&#xff0c;比传统的算法收敛速度更快。传统的LMS算法中&#xff0c;权值向量实时地被更新。这些更新可能会由于噪声的影响而变得不稳定。SVSLMS算法是一种改进的LMS算法&#xff0c;它采用了矢量处理的概念&#xff0c;利用信号和…

分布式锁的应用与疑惑

文章目录 一、为什么需要用分布式锁二、Redis实现分布式锁三、Zookeeper实现分布式锁 一、为什么需要用分布式锁 集群下&#xff0c;普通的锁&#xff0c;无法解决问题 集群下&#xff0c;保证安全需要使用分布式锁 二、Redis实现分布式锁 Redisson内部封装的RedLock实现分…

yolov9,使用自定义的数据训练推理

[源码 &#x1f40b;]( GitHub - WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information) [论文 &#x1f4d8;](arxiv.org/pdf/2402.13616.pdf) 论文摘要&#xff1a;本文介绍了一种新的目标检测…

Web服务器群集:OpenEuler 部署 LAMP(LNMP) 基础服务

目录 一、实验 1.环境 2. 网络配置 3. MobaXterm远程连接 4. apache 2.4.58 源码编译安装 5. php 8.3.1源码编译安装 6.配置httpd 连接 php-fpm 6. nginx 1.24.0源码编译安装 7. mysql 8.0.36安装 二、问题 1.MobaXterm设置右键复制粘贴 2.OpenEuler如何查看CPU的核…

网络防御保护3

一、双击热备 1&#xff0c;根据网段划分配置IP地址和安全区域 2&#xff0c;配置双机热备场景 主备场景配置 抢占延时仅对主设备生效。 hello报文周期时间--- 默认为1S&#xff0c;可以修改&#xff0c;但是&#xff0c;主备设备需要同时修改为相同值。 同步配置 双机热备的…

【网站项目】424学报稿件管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

一个注解实现频率控制

1.概述 抹茶项目是一个即时的IM通信项目&#xff0c;并且有着万人大群。但凡有几个人刷屏&#xff0c;那消息爆炸的场景&#xff0c;都不敢想象。如果我们需要对项目特定的接口进行频率控制&#xff0c;不仅是业务上的功能&#xff0c;同样也保护了项目的监控运行。而频控又是…

幻兽帕鲁(1.5.0)可视化管理工具(0.5.7 docker版)安装教程

文章目录 局域网帕鲁服务器部署教程帕鲁服务可视化工具安装配置服务器地址&#xff08;可跳过&#xff09;使用工具管理面板 1.5.0服务端RCON错误1.5.0服务端无法启动RCON端口 解决方法第一步&#xff1a;PalWorldSettings.ini配置第二步&#xff1a;修改PalServer.sh配置 局域…

数据结构--二叉排序树(Binary Search Tree,简称BST)

这里写自定义目录标题 二叉排序树二叉排序树与排序数组没有排序数组&#xff0c;链式存储链表的对比二叉排序树概念对于搜索操作&#xff0c;对于插入操作&#xff0c;对于删除操作&#xff0c; 分析删除节点代码运行结果 二叉排序树 二叉排序树与排序数组没有排序数组&#x…