【SpringBoot整合系列】SpringBoot整合Redis[附redis工具类源码]

news2024/11/20 12:26:43

目录

  • SpringBoot整合Redis
    • 1.下载和安装Redis
    • 2.新建工程,导入依赖
    • 3.添加配置
    • 4.先来几个基本的示例
      • 测试代码
      • 输出结果
      • 用redis客户端查看一下存储内容
    • 5.封装redis工具类
      • RedisKeyUtil
      • RedisStringUtil
      • RedisHashUtil
      • RedisListUtil
      • RedisSetUtil
      • RedisZsetUtil
      • 备注
    • 6.测试
      • 通用
      • string
  • Redis的注解式开发
    • 启动类添加开启缓存注解
    • 常用注解
      • @Cacheable注解
        • 解释:
        • 属性
        • 示例
      • @CachePut注解
        • 解释
        • 属性
        • 示例
        • 注意
      • @CacheEvict注解
        • 解释
        • 属性
        • 示例
      • 思考
        • 解决方案1:
        • 解决方案2:
      • @CacheConfig注解
        • 解释
      • @Caching注解
        • 解释

SpringBoot整合Redis

1.下载和安装Redis

略,可以看我之前的博客

2.新建工程,导入依赖

其中主要是redis依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.3</version>
            <scope>test</scope>
        </dependency>

3.添加配置

  • 两个重要的API:RedisTemplate 和 StringRedisTemplate
  • RedisTemplate 和 StringRedisTemplate提供了一系列opsForXxx()方法,返回XxxOperations对象,用来操作Xxx对象。
    • opsForValue():返回可操作String对象的ValueOperations对象;
    • opsForList():返回可操作List对象的ListOperations对象;
    • opsForSet():返回可操作Set对象的SetOperations对象;
    • opsForZset():返回可操作Zset对象的ZsetOperations对象;
    • opsForHash():返回可操作Hash对象的HashOperations对象;

4.先来几个基本的示例

测试代码

package cn.smbms;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;

@SpringBootTest
@Slf4j
class RedisdemoApplicationTests {
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Test
    void setAndGetValue() {
        redisTemplate.opsForValue().set("redisName", "张三");
        stringRedisTemplate.opsForValue().set("stringRedisName", "张三");
        log.info("写入两个字符串到Redis中完毕");
        String redisName = (String) redisTemplate.opsForValue().get("redisName");
        String stringRedisName = stringRedisTemplate.opsForValue().get("stringRedisName");
        log.info("从Redis中取出redisName的值是:{}",redisName);
        log.info("从Redis中取出stringRedisName的值是:{}",stringRedisName);
    }
}

输出结果

......cn.smbms.RedisdemoApplicationTests       : 写入两个字符串到Redis中完毕
......cn.smbms.RedisdemoApplicationTests       :Redis中取出redisName的值是:张三
......cn.smbms.RedisdemoApplicationTests       :Redis中取出stringRedisName的值是:张三

用redis客户端查看一下存储内容

在这里插入图片描述

  • 这些看着像是乱码,其实并不是乱码。
  • RedisTemplate 存储的数据通常是二进制的。Redis 是一个键值存储系统,它存储的值可以是字符串、二进制数据、甚至是序列化的对象。
  • RedisTemplate 是 Spring Data Redis 提供的一个类,用于在 Spring 应用中与 Redis 进行交互。
  • 它提供了一种在 Java 对象和 Redis 数据之间进行序列化和反序列化的机制。
  • 默认情况下,RedisTemplate 使用 JDK 的序列化机制将 Java 对象转换为二进制数据,并存储在 Redis 中。

5.封装redis工具类

  • 直接用RedisTemplate操作Redis,需要很多行代码,因此直接封装好一个RedisUtils,这样写代码更方便点。
  • 这个RedisUtils交给Spring容器实例化,使用时直接注解注入,节省代码,操作统一。

RedisKeyUtil

package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisKeyUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisKeyUtil.redisTemplate = redisTemplate;
    }
    /** -------------------key相关操作--------------------- */
    /**
     * 删除key
     *
     * @param key
     */
    public static void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 批量删除key
     *
     * @param keys
     */
    public static void delete(Collection<String> keys) {
        redisTemplate.delete(keys);
    }

    /**
     * 序列化key
     *
     * @param key
     * @return
     */
    public static byte[] dump(String key) {
        return redisTemplate.dump(key);
    }

    /**
     * 是否存在key
     *
     * @param key
     * @return
     */
    public static Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param timeout
     * @param unit
     * @return
     */
    public static Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param date
     * @return
     */
    public static Boolean expireAt(String key, Date date) {
        return redisTemplate.expireAt(key, date);
    }

    /**
     * 查找匹配的key
     *
     * @param pattern
     * @return
     */
    public static Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 将当前数据库的 key 移动到给定的数据库 db 当中
     *
     * @param key
     * @param dbIndex
     * @return
     */
    public static Boolean move(String key, int dbIndex) {
        return redisTemplate.move(key, dbIndex);
    }

    /**
     * 移除 key 的过期时间,key 将持久保持
     *
     * @param key
     * @return
     */
    public static Boolean persist(String key) {
        return redisTemplate.persist(key);
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @param unit
     * @return
     */
    public static Long getExpire(String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @return
     */
    public static Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 从当前数据库中随机返回一个 key
     *
     * @return
     */
    public static String randomKey() {
        return redisTemplate.randomKey();
    }

    /**
     * 修改 key 的名称
     *
     * @param oldKey
     * @param newKey
     */
    public static void rename(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * 仅当 newkey 不存在时,将 oldKey 改名为 newkey
     *
     * @param oldKey
     * @param newKey
     * @return
     */
    public static Boolean renameIfAbsent(String oldKey, String newKey) {
        return redisTemplate.renameIfAbsent(oldKey, newKey);
    }

    /**
     * 返回 key 所储存的值的类型
     *
     * @param key
     * @return
     */
    public static DataType type(String key) {
        return redisTemplate.type(key);
    }
}

RedisStringUtil

package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisStringUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisStringUtil.redisTemplate = redisTemplate;
    }
    /** -------------------string相关操作--------------------- */
    /**
     * 设置指定 key 的值
     *
     * @param key
     * @param value
     */
    public static void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取指定 key 的值
     *
     * @param key
     * @return
     */
    public static String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 返回 key 中字符串值的子字符
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static String getRange(String key, long start, long end) {
        return redisTemplate.opsForValue().get(key, start, end);
    }

    /**
     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
     *
     * @param key
     * @param value
     * @return
     */
    public static String getAndSet(String key, String value) {
        return redisTemplate.opsForValue().getAndSet(key, value);
    }

    /**
     * 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
     * @param key
     * @param offset
     * @return
     */
    public static Boolean getBit(String key, long offset) {
        return redisTemplate.opsForValue().getBit(key, offset);
    }

    /**
     * 批量获取
     *
     * @param keys
     * @return
     */
    public static List<String> multiGet(Collection<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
     *
     * @param key   位置
     * @param value 值,true为1, false为0
     * @return
     */
    public static boolean setBit(String key, long offset, boolean value) {
        return redisTemplate.opsForValue().setBit(key, offset, value);
    }

    /**
     * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
     *
     * @param key
     * @param value
     * @param timeout 过期时间
     * @param unit    时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
     *                秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
     */
    public static void setEx(String key, String value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 只有在 key 不存在时设置 key 的值
     *
     * @param key
     * @param value
     * @return 之前已经存在返回false, 不存在返回true
     */
    public static boolean setIfAbsent(String key, String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
     *
     * @param key
     * @param value
     * @param offset 从指定位置开始覆写
     */
    public static void setRange(String key, String value, long offset) {
        redisTemplate.opsForValue().set(key, value, offset);
    }

    /**
     * 获取字符串的长度
     *
     * @param key
     * @return
     */
    public static Long size(String key) {
        return redisTemplate.opsForValue().size(key);
    }

    /**
     * 批量添加
     *
     * @param maps
     */
    public static void multiSet(Map<String, String> maps) {
        redisTemplate.opsForValue().multiSet(maps);
    }

    /**
     * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
     *
     * @param maps
     * @return 之前已经存在返回false, 不存在返回true
     */
    public static boolean multiSetIfAbsent(Map<String, String> maps) {
        return redisTemplate.opsForValue().multiSetIfAbsent(maps);
    }

    /**
     * 增加(自增长), 负数则为自减
     *
     * @param key
     * @return
     */
    public static Long incrBy(String key, long increment) {
        return redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * @param key
     * @return
     */
    public static Double incrByFloat(String key, double increment) {
        return redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * 追加到末尾
     *
     * @param key
     * @param value
     * @return
     */
    public static Integer append(String key, String value) {
        return redisTemplate.opsForValue().append(key, value);
    }
}

RedisHashUtil

package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisHashUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisHashUtil.redisTemplate = redisTemplate;
    }
    /** -------------------hash相关操作------------------------- */
    /**
     * 获取存储在哈希表中指定字段的值
     *
     * @param key
     * @param field
     * @return
     */
    public static Object hGet(String key, String field) {
        return redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @return
     */
    public static Map<Object, Object> hGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @param fields
     * @return
     */
    public static List<Object> hMultiGet(String key, Collection<Object> fields) {
        return redisTemplate.opsForHash().multiGet(key, fields);
    }

    public static void hPut(String key, String hashKey, String value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public static void hPutAll(String key, Map<String, String> maps) {
        redisTemplate.opsForHash().putAll(key, maps);
    }

    /**
     * 仅当hashKey不存在时才设置
     *
     * @param key
     * @param hashKey
     * @param value
     * @return
     */
    public static Boolean hPutIfAbsent(String key, String hashKey, String value) {
        return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * 删除一个或多个哈希表字段
     *
     * @param key
     * @param fields
     * @return
     */
    public static Long hDelete(String key, Object... fields) {
        return redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 查看哈希表 key 中,指定的字段是否存在
     *
     * @param key
     * @param field
     * @return
     */
    public static boolean hExists(String key, String field) {
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param increment
     * @return
     */
    public static Long hIncrBy(String key, Object field, long increment) {
        return redisTemplate.opsForHash().increment(key, field, increment);
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param delta
     * @return
     */
    public static Double hIncrByFloat(String key, Object field, double delta) {
        return redisTemplate.opsForHash().increment(key, field, delta);
    }

    /**
     * 获取所有哈希表中的字段
     *
     * @param key
     * @return
     */
    public static Set<Object> hKeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * 获取哈希表中字段的数量
     *
     * @param key
     * @return
     */
    public static Long hSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    /**
     * 获取哈希表中所有值
     *
     * @param key
     * @return
     */
    public static List<Object> hValues(String key) {
        return redisTemplate.opsForHash().values(key);
    }

    /**
     * 迭代哈希表中的键值对
     *
     * @param key
     * @param options
     * @return
     */
    public static Cursor<Map.Entry<Object, Object>> hScan(String key, ScanOptions options) {
        return redisTemplate.opsForHash().scan(key, options);
    }
}

RedisListUtil

package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisListUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisListUtil.redisTemplate = redisTemplate;
    }

    /** ------------------------list相关操作---------------------------- */
    /**
     * 通过索引获取列表中的元素
     *
     * @param key
     * @param index
     * @return
     */
    public static String lIndex(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * 获取列表指定范围内的元素
     *
     * @param key
     * @param start 开始位置, 0是开始位置
     * @param end   结束位置, -1返回所有
     * @return
     */
    public static List<String> lRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 存储在list头部
     *
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPush(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPushAll(String key, String... value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPushAll(String key, Collection<String> value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * 当list存在的时候才加入
     *
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPushIfPresent(String key, String value) {
        return redisTemplate.opsForList().leftPushIfPresent(key, value);
    }

    /**
     * 如果pivot存在,再pivot前面添加
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public static Long lLeftPush(String key, String pivot, String value) {
        return redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPush(String key, String value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPushAll(String key, String... value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPushAll(String key, Collection<String> value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * 为已存在的列表添加值
     *
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPushIfPresent(String key, String value) {
        return redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * 在pivot元素的右边添加值
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public static Long lRightPush(String key, String pivot, String value) {
        return redisTemplate.opsForList().rightPush(key, pivot, value);
    }

    /**
     * 通过索引设置列表元素的值
     *
     * @param key
     * @param index 位置
     * @param value
     */
    public static void lSet(String key, long index, String value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * 移出并获取列表的第一个元素
     *
     * @param key
     * @return 删除的元素
     */
    public static String lLeftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return
     */
    public static String lBLeftPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().leftPop(key, timeout, unit);
    }

    /**
     * 移除并获取列表最后一个元素
     *
     * @param key
     * @return 删除的元素
     */
    public static String lRightPop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return
     */
    public static String lBRightPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPop(key, timeout, unit);
    }

    /**
     * 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
     *
     * @param sourceKey
     * @param destinationKey
     * @return
     */
    public static String lRightPopAndLeftPush(String sourceKey, String destinationKey) {
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
                destinationKey);
    }

    /**
     * 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param sourceKey
     * @param destinationKey
     * @param timeout
     * @param unit
     * @return
     */
    public static String lBRightPopAndLeftPush(String sourceKey, String destinationKey,
                                               long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
                destinationKey, timeout, unit);
    }

    /**
     * 删除集合中值等于value得元素
     *
     * @param key
     * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;
     *              index<0, 从尾部开始删除第一个值等于value的元素;
     * @param value
     * @return
     */
    public static Long lRemove(String key, long index, String value) {
        return redisTemplate.opsForList().remove(key, index, value);
    }

    /**
     * 裁剪list
     *
     * @param key
     * @param start
     * @param end
     */
    public static void lTrim(String key, long start, long end) {
        redisTemplate.opsForList().trim(key, start, end);
    }

    /**
     * 获取列表长度
     *
     * @param key
     * @return
     */
    public static Long lLen(String key) {
        return redisTemplate.opsForList().size(key);
    }
}

RedisSetUtil

package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisSetUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisSetUtil.redisTemplate = redisTemplate;
    }
    /** --------------------set相关操作-------------------------- */
    /**
     * set添加元素
     *
     * @param key
     * @param values
     * @return
     */
    public static Long sAdd(String key, String... values) {
        return redisTemplate.opsForSet().add(key, values);
    }

    /**
     * set移除元素
     *
     * @param key
     * @param values
     * @return
     */
    public static Long sRemove(String key, Object... values) {
        return redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 移除并返回集合的一个随机元素
     *
     * @param key
     * @return
     */
    public static String sPop(String key) {
        return redisTemplate.opsForSet().pop(key);
    }

    /**
     * 将元素value从一个集合移到另一个集合
     *
     * @param key
     * @param value
     * @param destKey
     * @return
     */
    public static Boolean sMove(String key, String value, String destKey) {
        return redisTemplate.opsForSet().move(key, value, destKey);
    }

    /**
     * 获取集合的大小
     *
     * @param key
     * @return
     */
    public static Long sSize(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 判断集合是否包含value
     *
     * @param key
     * @param value
     * @return
     */
    public static Boolean sIsMember(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 获取两个集合的交集
     *
     * @param key
     * @param otherKey
     * @return
     */
    public static Set<String> sIntersect(String key, String otherKey) {
        return redisTemplate.opsForSet().intersect(key, otherKey);
    }

    /**
     * 获取key集合与多个集合的交集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sIntersect(String key, Collection<String> otherKeys) {
        return redisTemplate.opsForSet().intersect(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long sIntersectAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKey,
                destKey);
    }

    /**
     * key集合与多个集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long sIntersectAndStore(String key, Collection<String> otherKeys,
                                          String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKeys,
                destKey);
    }

    /**
     * 获取两个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sUnion(String key, String otherKeys) {
        return redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * 获取key集合与多个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sUnion(String key, Collection<String> otherKeys) {
        return redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的并集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long sUnionAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * key集合与多个集合的并集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long sUnionAndStore(String key, Collection<String> otherKeys,
                                      String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 获取两个集合的差集
     *
     * @param key
     * @param otherKey
     * @return
     */
    public static Set<String> sDifference(String key, String otherKey) {
        return redisTemplate.opsForSet().difference(key, otherKey);
    }

    /**
     * 获取key集合与多个集合的差集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sDifference(String key, Collection<String> otherKeys) {
        return redisTemplate.opsForSet().difference(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的差集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long sDifference(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKey,
                destKey);
    }

    /**
     * key集合与多个集合的差集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long sDifference(String key, Collection<String> otherKeys,
                                   String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKeys,
                destKey);
    }

    /**
     * 获取集合所有元素
     *
     * @param key
     * @return
     */
    public static Set<String> setMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 随机获取集合中的一个元素
     *
     * @param key
     * @return
     */
    public static String sRandomMember(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }

    /**
     * 随机获取集合中count个元素
     *
     * @param key
     * @param count
     * @return
     */
    public static List<String> sRandomMembers(String key, long count) {
        return redisTemplate.opsForSet().randomMembers(key, count);
    }

    /**
     * 随机获取集合中count个元素并且去除重复的
     *
     * @param key
     * @param count
     * @return
     */
    public static Set<String> sDistinctRandomMembers(String key, long count) {
        return redisTemplate.opsForSet().distinctRandomMembers(key, count);
    }

    /**
     * @param key
     * @param options
     * @return
     */
    public static Cursor<String> sScan(String key, ScanOptions options) {
        return redisTemplate.opsForSet().scan(key, options);
    }
}

RedisZsetUtil

package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Set;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisZsetUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisZsetUtil.redisTemplate = redisTemplate;
    }

    /**------------------zSet相关操作--------------------------------*/
    /**
     * 添加元素,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @param score
     * @return
     */
    public static Boolean zAdd(String key, String value, double score) {
        return redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * @param key
     * @param values
     * @return
     */
    public static Long zAdd(String key, Set<ZSetOperations.TypedTuple<String>> values) {
        return redisTemplate.opsForZSet().add(key, values);
    }

    /**
     * @param key
     * @param values
     * @return
     */
    public static Long zRemove(String key, Object... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     * 增加元素的score值,并返回增加后的值
     *
     * @param key
     * @param value
     * @param delta
     * @return
     */
    public static Double zIncrementScore(String key, String value, double delta) {
        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
    }

    /**
     * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @return 0表示第一位
     */
    public static Long zRank(String key, Object value) {
        return redisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 返回元素在集合的排名,按元素的score值由大到小排列
     *
     * @param key
     * @param value
     * @return
     */
    public static Long zReverseRank(String key, Object value) {
        return redisTemplate.opsForZSet().reverseRank(key, value);
    }

    /**
     * 获取集合的元素, 从小到大排序
     *
     * @param key
     * @param start 开始位置
     * @param end   结束位置, -1查询所有
     * @return
     */
    public static Set<String> zRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 获取集合元素, 并且把score值也获取
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zRangeWithScores(String key, long start,
                                                                          long end) {
        return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
    }

    /**
     * 根据Score值查询集合元素
     *
     * @param key
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static Set<String> zRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
    }

    /**
     * 根据Score值查询集合元素, 从小到大排序
     *
     * @param key
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zRangeByScoreWithScores(String key,
                                                                                 double min, double max) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zRangeByScoreWithScores(String key,
                                                                                 double min, double max, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,
                start, end);
    }

    /**
     * 获取集合的元素, 从大到小排序
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Set<String> zReverseRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     * 获取集合的元素, 从大到小排序, 并返回score值
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zReverseRangeWithScores(String key,
                                                                                 long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(key, start,
                end);
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Set<String> zReverseRangeByScore(String key, double min,
                                                   double max) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zReverseRangeByScoreWithScores(
            String key, double min, double max) {
        return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key,
                min, max);
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    public static Set<String> zReverseRangeByScore(String key, double min,
                                                   double max, long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max,
                start, end);
    }

    /**
     * 根据score值获取集合元素数量
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Long zCount(String key, double min, double max) {
        return redisTemplate.opsForZSet().count(key, min, max);
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public static Long zSize(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public static Long zZCard(String key) {
        return redisTemplate.opsForZSet().zCard(key);
    }

    /**
     * 获取集合中value元素的score值
     *
     * @param key
     * @param value
     * @return
     */
    public static Double zScore(String key, Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 移除指定索引位置的成员
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Long zRemoveRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().removeRange(key, start, end);
    }

    /**
     * 根据指定的score值的范围来移除成员
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Long zRemoveRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
    }

    /**
     * 获取key和otherKey的并集并存储在destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long zUnionAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long zUnionAndStore(String key, Collection<String> otherKeys,
                                      String destKey) {
        return redisTemplate.opsForZSet()
                .unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 交集
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long zIntersectAndStore(String key, String otherKey,
                                          String destKey) {
        return redisTemplate.opsForZSet().intersectAndStore(key, otherKey,
                destKey);
    }

    /**
     * 交集
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long zIntersectAndStore(String key, Collection<String> otherKeys,
                                          String destKey) {
        return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys,
                destKey);
    }

    /**
     * @param key
     * @param options
     * @return
     */
    public static Cursor<ZSetOperations.TypedTuple<String>> zScan(String key, ScanOptions options) {
        return redisTemplate.opsForZSet().scan(key, options);
    }
}

备注

为了方便操作,也可以把这几个类合并到一个RedisUtil类中

6.测试

随便写几个测试用例了

通用

    @Test
    void redisKey() {
        Set<String> keys = RedisKeyUtil.keys("*");
        keys.forEach(key -> {
            log.info("key:{}",key);
        });
        RedisKeyUtil.delete("userName");
        RedisKeyUtil.delete(keys);
        boolean isExist = RedisKeyUtil.hasKey("userName");
        boolean at = RedisKeyUtil.expire("userName", 10, TimeUnit.SECONDS);
        long expire = RedisKeyUtil.getExpire("userName");
    }

string

    @Test
    void redisStringUtil() {
        RedisStringUtil.set("userName", "系统管理员");
        log.info("写入userName到Redis中完毕");
        String userName = RedisStringUtil.get("userName");
        log.info("从Redis中取出userName的值是:{}",userName);
    }

Redis的注解式开发

  • 1.注意:一般开发中小型快速应用,适合redis注解开发。但是想要合理点的设置缓存,建议还是手动配置
  • 2.被缓存的实体类记得实现Serializable接口

启动类添加开启缓存注解

@SpringBootApplication
@EnableCaching
public class RedisdemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisdemoApplication.class, args);
    }
}

常用注解

@Cacheable注解

解释:
  • 先从redis数据库中按照当前key查找,有没有;
  • 如果redis中有,是不会走当前该方法的;
  • 如果没有再调用方法返回结果,如果结果不为null将其缓存到数据库中(一般用于find)
属性
  • value:key的一部分(前缀),主要是指明数据放在那个key范围
  • key:key的主体,#p0:指明取出第一个参数 #p1:指明取出第二个参数。。。依此类推;或者#参数名
  • unless:结果为true,将当前的数据结果不保存到redis,#result:指明取出数据库中返回的结果
  • condition 结果如果为true,将当前数据保存到redis
示例

mapper层

@Mapper//图省事,在这里加上@Mapper注解,否则在启动类上加@MapperScan("cn.smbms.mapper")
public interface UserMapper {
    @Select("select * from smbms_user where id=#{id}")
    User selectUserById(int id);
}

service层添加缓存注解

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    @Cacheable(value = "user",key = "#id",unless = "#result == null",condition = "#id > 1")
    public User getUserDetail(int id){
        return userMapper.selectUserById(id);
    }
}

测试

    @Test
    public void select(){
        System.out.println(userService.getUserDetail(1));//不会添加到缓存
        System.out.println(userService.getUserDetail(99));//结果为空,不会加入到缓存
        System.out.println(userService.getUserDetail(7));//会添加到缓存
    }

在这里插入图片描述
当再次查询ID为7的数据时,就会从redis中获取,而不会再查询数据库了
测试

    @Test
    public void select(){
        //System.out.println(userService.getUserDetail(1));//不会添加到缓存
        //System.out.println(userService.getUserDetail(99));//结果为空,不会加入到缓存
        System.out.println(userService.getUserDetail(7));//会添加到缓存
    }

返回结果:没有SQL记录

2024-04-26 14:10:37.030  INFO 23524 --- [           main] cn.smbms.RedisdemoApplicationTests       : Started RedisdemoApplicationTests in 5.091 seconds (JVM running for 6.098)
User(id=7, userCode=wangyang, userName=王洋, userPassword=1, gender=2, birthday=Fri Dec 31 00:00:00 CST 1982, phone=13444561124, address=北京市海淀区西二旗辉煌国际16, userRole=3, createdBy=1, creationDate=Wed Jun 11 19:09:07 CST 2014, modifyBy=null, modifyDate=null)
2024-04-26 14:10:38.167  INFO 23524 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

@CachePut注解

解释
  • 主要用于向数据库中插入数据,向数据中插入数据的时候,会将返回的int类型,放入redis中缓存,当然是有选择性的(一般用于insert)
属性
  • value:key的一部分,命名空间
  • key:指定key的名称
  • unless:满足条件,则不将返回的结果放入redis
  • condition: 满足条件,则将返回的结果放入redis
示例

mapper层

    @Insert("insert into smbms_user(userCode,userName,phone,address,userRole) values(#{userCode},#{userName},#{phone},#{address},#{userRole})")
    @Options(useGeneratedKeys = true, keyProperty = "id")//返回自增主键
    int insertUser(User user);

service层

    @CachePut(value = "user",key = "#user.id",unless = "#result == null",condition = "#user.userRole == 3")
    public User saveUser(User user){
        userMapper.insertUser(user);
        return user;
    }

测试

    @Test
    public void save(){
        System.out.println(userService.saveUser(new User("aaa","AAA","180","郑州",2)));//userRole!=3,不会缓存
        System.out.println(userService.saveUser(new User("bbb","BBB","138","南京",3)));//userRole==3,会缓存
    }

在这里插入图片描述

注意

修改也是同样的操作

@CacheEvict注解

解释

满足条件则移除当前key在redis中的数据(一般用于update/delete)

属性
  • value: 同理命名空间
  • key: key名称
  • condition:满足什么条件从缓存中移除指定的key
  • AllEntries:true/false 是否移除命名空间下的所有key
示例

mapper层

    @Delete("delete from smbms_user where id=#{id}")
    int deleteUserById(int id);

service层

    @CacheEvict(value = "user",key = "#id",allEntries = true)
    public boolean deleteUser(int id){
        return userMapper.deleteUserById(id) > 0;
    }

测试

    @Test
    public void delete(){
        System.out.println(userService.deleteUser(82));
    }

此时会把user这个命名空间下所有的数据都删除,因为allEntries = true
在这里插入图片描述
重新添加几条数据
在这里插入图片描述service层的删除方法去掉allEntries = true,或者设置为false,再次测试

    @Test
    public void delete(){
        System.out.println(userService.deleteUser(84));
    }

在这里插入图片描述

思考

  • 我们知道如果进行查询的时候,会将数据缓存到redis中。
  • 一旦进行增删改,那么原本数据库中的数据可能会发生变化,那么增删改成功后,应该要指定的移除指定key的缓存。
  • 但是我们通过@CaheEvict移除指定key的数据,发现并不能行的通。
解决方案1:
  • @CaheEvict(value=“nameSpace”,allEntries=true),移除这个命名空间下的所有数据
解决方案2:
  • 通过redisTemplate手动移除相关联的key的数据(相对来说麻烦点)

@CacheConfig注解

解释
  • 所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的
  • 如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用@CacheConfig。
    @Cacheable(key = "#id",unless = "#result == null",condition = "#id > 1")
    public User getUserDetail(int id){
        return userMapper.selectUserById(id);
    }

@Caching注解

解释
  • 有时候我们可能组合多个Cache注解使用;
  • 比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;
  • 此时就需要@Caching组合多个注解标签了。
    @Caching(put = {
	    @CachePut(value = "user", key = "#user.id"),
	    @CachePut(value = "user", key = "#user.userCode"),
	    @CachePut(value = "user", key = "#user.phone")
    })
    public User save(User user) {
     ...
    }

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

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

相关文章

Pytorch 之torch.nn初探 卷积--Convolution Layers

任务描述 本关任务&#xff1a; 本关提供了一个Variable 类型的变量input&#xff0c;按照要求创建一 Conv1d变量conv&#xff0c;对input应用卷积操作并赋值给变量 output&#xff0c;并输出output 的大小。 相关知识 卷积的本质就是用卷积核的参数来提取原始数据的特征&a…

成都金沙国际学校招生介绍

成都金沙国际学校于2017年9月正式开学&#xff0c;涵盖了初中、高中学段&#xff0c;致力于为川南地区培育更多更优秀的国际化人才&#xff0c;是一所真正意义上的外国语教育窗口学校。校园环境优美&#xff0c;教学设施全市一流&#xff0c;师资团队精良&#xff0c;游学、留学…

绘制签章 乱码问题 (踩坑日记)

签章汉字乱码问题 原因:我们在docker上因为没有汉字字体需要我们手动把文件打进去 注意点:如果开启了打包过滤加上字体不过滤 绘制签章转载

系统服务(22年国赛)—— 磁盘管理(压缩去重)

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; 系统服务&#xff08;22年国赛&#xff09;—— 磁盘管理(压缩&&去重)https://myweb.myskillstree.cn/90.html 目录 StorageSrv 安装并创建vdo 将…

3122.使矩阵满足条件的最少操作次数

周赛第三题,知道要用动态规划,但是不知道怎么回到子问题 显然根据题意我们需要让每一列都相同,但是相邻列不能选择同一种数字,观察到数据nums[i]介于0-9,我们就以此为突破口. 首先我们用count[n][10], count[i][j]记录第i1列值为j的元素个数,转移方程如下: dfs(i,pre) max(dfs…

Vue基于高德地图API封装一个地图组件

一、参考资料 高德开放平台 | 高德地图API (amap.com) 二、安装及配置 pnpm i vuemap/vue-amap --save man.ts 密钥及安全密钥需要自己到高德地图开放平台控制台获取. import { createApp } from vue import App from ./App.vue import router from ./router i…

Orange3数据可视化(组件概览)

概要 大家见过Orange3提供的丰富数据可视化组件吗&#xff1f; Orange3为您提供了一系列生动的图表工具&#xff0c;包括树图、箱线图、小提琴图、分布图、散点图、折线图、条形图、筛图、马赛克图、自由投影、线性投影、雷达图、热力图、韦恩图、轮廓图、毕达哥拉斯树、毕达哥…

Python | Leetcode Python题解之第48题旋转图像

题目&#xff1a; 题解&#xff1a; class Solution:def rotate(self, matrix: List[List[int]]) -> None:n len(matrix)# 水平翻转for i in range(n // 2):for j in range(n):matrix[i][j], matrix[n - i - 1][j] matrix[n - i - 1][j], matrix[i][j]# 主对角线翻转for …

鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元

任务即线程 在鸿蒙内核中&#xff0c;广义上可理解为一个任务就是一个线程 官方是怎么描述线程的 基本概念 从系统的角度看&#xff0c;线程是竞争系统资源的最小运行单元。线程可以使用或等待CPU、使用内存空间等系统资源&#xff0c;并独立于其它线程运行。 鸿蒙内核每个…

OS对软件的管理,进程,PCB、子进程

进程 可执行程序加载到内存中&#xff0c;操作系统为内个程序都形成一个PCB对象&#xff08;结构体对象&#xff09;&#xff0c;PCB里存放着这个程序的所有的属性。进程可执行程序PCB &#xff0c;CPU执行程序也是先通过该程序的PCB找到相应的程序代码&#xff0c;然后一条一…

鸿蒙内核源码分析(时钟任务篇)

时钟概念 时间是非常重要的概念&#xff0c;我们整个学生阶段有个东西很重要,就是校园铃声. 它控制着上课,下课,吃饭,睡觉的节奏.没有它学校的管理就乱套了,老师拖课想拖多久就多久,那可不行,下课铃声一响就是在告诉老师时间到了,该停止了让学生HAPPY去了. 操作系统也一样&…

Flutter基础语法

Flutter概要 Flutter目录结构 文件夹 作用 android android 平台相关代码 ios ios平台相关代码 lib flutter相关代码&#xff0c;我们主要编写的代码就在这个文件夹中 test 用于存放测试的代码 pubspec.yaml 配置文件&#xff0c;一般存放一些第三方库的依赖 Flutt…

【研发管理】产品经理知识体系-产品设计与开发工具

导读&#xff1a;产品设计与开发工具的重要性体现在多个方面&#xff0c;它们对于产品的成功开发、质量提升以及市场竞争力都具有至关重要的影响。产品设计工具可以帮助设计师更高效地创建和优化产品原型。开发工具在产品开发过程中发挥着至关重要的作用。产品设计与开发工具还…

细致讲解——不同类型LSA是作用以及相互之间的联系

目录 一.常见的LSA类型 二.OSPF特殊区域 1.区域类型 2.stub区域和totally stub区域 &#xff08;1&#xff09;stub区域 &#xff08;2&#xff09;totally stub区域 3.nssa区域和totally nssa区域 &#xff08;1&#xff09;nssa区域 &#xff08;2&#xff09;totall…

tensorflow_decision_forests\tensorflow\ops\inference\inference.so not found

恰好有一个帖子提到了py3.10里面的解决方案 pip install --user tensorflow2.11.0My tensorflow version is 2.11.0 and my tensorflow_decision_forests version is 1.2.0 so those should be compatible. I also am using Python version 3.10.11原文链接&#xff1a; http…

基于SpringBoot+VueHome F家居系统的设计与实现

系统介绍 该Home F家居系统采用B/S架构、前后端分离以及MVC模型进行设计&#xff0c;并采用Java语言以及SpringBoot框架进行开发。本系统主要设计并完成了用户注册、登录&#xff0c;购买家具过程、个人信息修改等&#xff0c;商家添加家具信息、对家具进行发货&#xff0c;管理…

假定输入字符串只包含字母和*号。编写函数fun:只删除字符串前导和尾部的*号,串中字母之间的*号都不删除。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法完整代码和详细的解析。 题干 假定…

第10章:知识整合提示

这种技术使用模型的预先存在的知识&#xff0c;来整合新、旧信息&#xff0c;助力我们全面认知特定的主题。 与ChatGPT配合时&#xff0c;只需提供新信息与任务目标&#xff0c;加上清晰的提示词&#xff0c;它就能为你生成满意文本。 例 1:知识整合 任务&#xff1a;将新信息…

YOLOv9最新改进系列:完美融合即插即用的涨点模块之注意力机制(SEAttention)。

YOLOv9最新改进系列&#xff1a;完美融合即插即用的涨点模块之注意力机制&#xff08;SEAttention&#xff09;。 YOLOv9原文链接戳这里&#xff0c;原文全文翻译请关注B站Ai学术叫叫首er B站全文戳这里&#xff01; 详细的改进教程以及源码&#xff0c;戳这&#xff01;戳这…