redis zremove删除不掉【bug】

redis zremove删除不掉【bug】

前言

2024-4-12 20:35:21

以下内容源自《【bug】》
仅供学习交流使用

版权

禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://blog.csdn.net/qq_51625007
禁止其他平台发布时删除以上此话

redis zremove删除不掉

测试一

  1. 调用添加数据:testAddData20
  2. 调用修改数据:testUpdateData
  3. 调用删除方法:testRemoveData20

结果:调用删除新的数据,旧的数据就会重新出现

java 复制代码
1.
{date=[2024-04-13], rate1=[20], rate2=[20], id=[20]}
2.
true
{date=[2024-04-13], rate1=[22], rate2=[22], id=[20]}
3.
1
{date=[2024-04-13], rate1=[20], rate2=[20], id=[20]}

测试二:

  1. 调用添加数据:testAddData
  2. 调用删除方法:testRemoveData20

结果:删除成功,只有数据完全一样才行

java 复制代码
1.
{date=[2024-04-13, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12], rate1=[20, 9, 8, 7, 6, 5, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 3, 2, 1], rate2=[20, 9, 8, 7, 6, 5, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 3, 2, 1], id=[20, 9, 8, 7, 6, 5, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 3, 2, 1]}
2.
1
{date=[2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12, 2024-04-12], rate1=[9, 8, 7, 6, 5, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 3, 2, 1], rate2=[9, 8, 7, 6, 5, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 3, 2, 1], id=[9, 8, 7, 6, 5, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 3, 2, 1]}

错误产生

为什么可以修改,但是不能删除

在上面的代码中,虽然使用了自定义序列化器和比较方法来实现根据特定条件或属性删除数据,但是在实际操作中,Redis有序集合的remove方法确实只能删除完全相同的数据。

这是因为在Redis的有序集合中,元素是通过score进行排序的,而remove方法是根据元素的值来删除的。如果元素的值完全相同,那么remove方法可以成功删除。但是如果元素的值中的某些属性或条件不同,即使其他属性相同,remove方法也无法删除这样的数据。

因此,如果希望根据特定属性或条件删除数据,可以考虑使用其他数据结构或方法来实现,比如使用Redis的哈希表来存储数据,然后通过特定的属性作为键来删除数据。或者在应用层进行数据的筛选和删除操作,然后再写回Redis中。

不能根据equals方法判断的吗

对于Java中的对象,可以通过重写equals方法来自定义判断两个对象是否相等。但是在Redis中,数据是以字符串或字节数组的形式存储的,并没有对对象的equals方法进行支持。

在Redis中,有序集合的remove方法是根据元素的值来删除的,而不是根据对象的equals方法。只有完全相同的值才可以被成功删除,否则无法删除。

如果希望根据对象的equals方法来判断是否删除数据,通常需要在应用层进行操作,先获取到数据再进行比较,然后再删除数据。或者可以使用其他数据结构或方法来实现根据对象的equals方法来删除数据。Redis本身并不提供根据对象的equals方法进行删除的功能。

应该是与序列化和反序列化有关。

相关资源

EldData

java 复制代码
package com.jsss.echarts.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.sql.Date;
import java.util.Objects;


@Data
@NoArgsConstructor
@AllArgsConstructor

public class EldData {
    String id;
    Integer rate1;
    Integer rate2;
    Date date;

 public EldData(String id, Date date) {
        this.id = id;
        this.date = date;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        EldData eldData = (EldData) o;
        return Objects.equals(id, eldData.id) && Objects.equals(date, eldData.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, date);
    }
    
    @Override
    public String toString() {
        return "EldData{" +
                "rate1=" + rate1 +
                ", rate2=" + rate2 +
                ", date=" + date +
                '}';
    }
}

EchartsTest

java 复制代码
package com.jsss.echarts.service;

import com.jsss.echarts.entity.EldData;
import com.jsss.utils.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

@Service
public class DataService implements Constant {


    @Autowired
    RedisTemplate redisTemplate;


    //返回数据链表
    public HashMap<String,ArrayList> searchMap(Integer userId){
        HashMap<String,ArrayList> map=new HashMap<>();
        List<EldData> dataList = search(userId);

        List<String> fieldNames = new ArrayList<>();
        Class<?> dataClass = EldData.class;

        // 获取 OldData 类的所有属性名
        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            fieldNames.add(field.getName());
            map.put(field.getName(),new ArrayList<>());
        }


        for (EldData data : dataList) {
            for (String fieldName : fieldNames) {
                ArrayList<Object> rowData =map.get(fieldName);
                try {
                    Field field = dataClass.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    rowData.add(field.get(data));
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                map.put(fieldName,rowData);
            }

        }
        return map;
    }

    //搜索数据
    public List<EldData> search(Integer userId) {
        String key= ELD_DATA +userId;
        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, 19);// 获取分数最高的20个数据

        return set !=null?new ArrayList<>(set):new ArrayList<>();

    }

    // 将数据存储到有序集合中,分数为日期的时间戳
    public boolean addData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().add(key, data,data.getDate().getTime());
    }

    // 更新数据,如果数据已存在则会覆盖
    public boolean updateData(Integer userId, EldData newData) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().add(key, newData, newData.getDate().getTime());
    }

    // 删除指定的数据
    public long removeData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().remove(key, data);
    }

    @Test
    public void test2() {
        System.out.println("1.");
        testAddData20();
        System.out.println("2.");
        testUpdateData();
        System.out.println("3.");
        testRemoveData();

    }

}

DataService

java 复制代码
package com.jsss.echarts.service;

import com.jsss.echarts.entity.EldData;
import com.jsss.utils.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

@Service
public class DataService implements Constant {


    @Autowired
    RedisTemplate redisTemplate;


    //返回数据链表
    public HashMap<String,ArrayList> searchMap(Integer userId){
        HashMap<String,ArrayList> map=new HashMap<>();
        List<EldData> dataList = search(userId);

        List<String> fieldNames = new ArrayList<>();
        Class<?> dataClass = EldData.class;

        // 获取 OldData 类的所有属性名
        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            fieldNames.add(field.getName());
            map.put(field.getName(),new ArrayList<>());
        }


        for (EldData data : dataList) {
            for (String fieldName : fieldNames) {
                ArrayList<Object> rowData =map.get(fieldName);
                try {
                    Field field = dataClass.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    rowData.add(field.get(data));
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                map.put(fieldName,rowData);
            }

        }
        return map;
    }

    //搜索数据
    public List<EldData> search(Integer userId) {
        String key= ELD_DATA +userId;
        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, 19);// 获取分数最高的20个数据

        return set !=null?new ArrayList<>(set):new ArrayList<>();

    }

    // 将数据存储到有序集合中,分数为日期的时间戳
    public boolean addData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().add(key, data,data.getDate().getTime());
    }

    // 更新数据,如果数据已存在则会覆盖
    public boolean updateData(Integer userId, EldData newData) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().add(key, newData, newData.getDate().getTime());
    }

    // 删除指定的数据
    public long removeData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().remove(key, data);
    }


}

解决

不知道怎么解决

修改更新业务

先删除旧的,再添加新的

保证只有一个equals对象

java 复制代码
   // 将数据存储到有序集合中,分数为日期的时间戳
    public boolean addData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().add(key, data,data.getDate().getTime());
    }

    // 更新数据,先删除数据,后增加新数据
    public boolean updateData(Integer userId,EldData oldData,EldData newData) {
        long res=removeData(userId,oldData);
        if (res==0){
            //没有旧数据,就修改失败
            return false;
        }
        return addData(userId, newData);
    }

    // 删除指定的数据
    public long removeData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().remove(key, data);
    }

对应的测试方法

java 复制代码
    @Test
    public void testUpdateData() {
        EldData oldData=new EldData(String.valueOf(20),20,20,date);
        EldData newData=new EldData(String.valueOf(20),22,22,date);
        System.out.println(dataService.updateData(userId, oldData,newData));
        testSearchMap();
    }

测试test1,结果:

java 复制代码
1.
{date=[2024-04-13], rate1=[20], rate2=[20], id=[20]}
2.
true
{date=[2024-04-13], rate1=[22], rate2=[22], id=[20]}
3.
1
{date=[], rate1=[], rate2=[], id=[]}

最后

2024-4-12 21:31:23

我们都有光明的未来

祝大家考研上岸
祝大家工作顺利
祝大家得偿所愿
祝大家如愿以偿
点赞收藏关注哦

相关推荐
CoderIsArt32 分钟前
Redis的三种模式:主从模式,哨兵与集群模式
数据库·redis·缓存
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck1 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei1 小时前
java的类加载机制的学习
java·学习
Yaml43 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~3 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616883 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7894 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java4 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~5 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust