最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

sky-take-out項(xiàng)目中Redis的使用示例詳解

 更新時(shí)間:2025年07月23日 11:37:03   作者:iam_leeqing  
SpringCache是Spring的緩存抽象層,通過注解簡化緩存管理,支持Redis等提供者,適用于方法結(jié)果緩存、更新和刪除操作,但無法實(shí)現(xiàn)Redis的高級功能(如數(shù)據(jù)結(jié)構(gòu)、事務(wù)、分布式鎖),本文給大家介紹sky-take-out項(xiàng)目中Redis的使用,感興趣的朋友一起看看吧

Spring Cache 是 Spring Framework 提供的一個(gè)抽象層,用于簡化應(yīng)用程序中的緩存管理。它允許開發(fā)者以聲明式的方式將緩存添加到應(yīng)用中,而不需要手動(dòng)編寫冗長的緩存邏輯代碼。Spring Cache 通過提供一系列注解和配置選項(xiàng),使得集成緩存變得非常簡單。將 Redis 集成到 Spring 應(yīng)用程序中,并將其作為 Spring Cache 的緩存提供者。這樣做的好處是可以在開發(fā)過程中專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),只需通過 Spring Cache 提供的簡單注解即可完成復(fù)雜的緩存管理任務(wù)。與此同時(shí),你還能享受到 Redis 提供的高效性能和豐富的功能特性。這種方法不僅提高了開發(fā)效率,還增強(qiáng)了應(yīng)用的可擴(kuò)展性和性能表現(xiàn)。

Spring Cache主要特性

  1. 聲明式緩存:通過使用注解(如 @Cacheable, @CachePut, @CacheEvict 等),可以非常方便地在方法上定義緩存行為。
  2. 多種緩存實(shí)現(xiàn)支持:Spring Cache 抽象層支持多種緩存解決方案,包括但不限于 Ehcache, Hazelcast, Infinispan, JCache (JSR-107), Guava Cache, Caffeine, Redis 等。
  3. 靈活的配置:可以通過 XML 配置、Java Config 或者自動(dòng)配置來設(shè)置緩存管理器(Cache Manager)。
  4. 條件緩存:可以根據(jù)特定條件決定是否執(zhí)行緩存操作(例如,使用 condition 屬性)。
  5. SpEL 支持:可以在注解中使用 Spring Expression Language (SpEL) 來動(dòng)態(tài)指定緩存鍵或其他屬性值。

核心注解

1.@Cacheable

此注解通常用于查詢操作,當(dāng)調(diào)用被注解的方法時(shí),如果緩存中存在對應(yīng)的數(shù)據(jù),則直接返回緩存結(jié)果,而不是執(zhí)行方法體。

    @GetMapping("/list")
    @ApiOperation("根據(jù)分類id查詢套餐")
    @Cacheable(cacheNames = "setmealCache",key = "#categoryId")
    public Result<List<Setmeal>> list(Long categoryId) {
        Setmeal setmeal = new Setmeal();
        setmeal.setCategoryId(categoryId);
        setmeal.setStatus(StatusConstant.ENABLE);
        List<Setmeal> list = setmealService.list(setmeal);
        return Result.success(list);
    }
  • value: 指定緩存的名字。
  • key: 可選參數(shù),用來指定緩存的鍵??梢允褂?SpEL 表達(dá)式。

2.@CachePut

@Cacheable 不同,@CachePut 總是會(huì)執(zhí)行方法,并將方法的結(jié)果放入緩存中。適用于更新操作。

    @GetMapping("/{id}")
    @ApiOperation("根據(jù)id查詢套餐")
    @CachePut(cacheNames = "setmealCache",key = "#categoryId")
    public Result<SetmealVO> getById(@PathVariable Long id) {
        SetmealVO setmealVO = setmealService.getByIdWithDish(id);
        return Result.success(setmealVO);
    }

3.@CacheEvict

用于清除緩存,適用于刪除或無效化數(shù)據(jù)的操作。

    @PostMapping
    @ApiOperation("新增套餐")
    @CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")
    public Result save(@RequestBody SetmealDTO setmealDTO) {
        setmealService.saveWithDish(setmealDTO);
        return Result.success();
    }
  • value: 指定緩存的名字。
  • key: 用來指定緩存的鍵??梢允褂?SpEL 表達(dá)式。
@CacheEvict(cacheNames = "setmealCache", allEntries = true)
public Result startOrStop(@PathVariable Integer status, Long id) {
    setmealService.startOrStop(status, id);
    return Result.success();
}

@CacheEvict(cacheNames = "setmealCache", allEntries = true) 被用來清除名為 setmealCache 的緩存中的所有條目。

  • cacheNames/value:指定要操作的緩存名稱。在這個(gè)例子中是 "setmealCache"。這兩個(gè)屬性是等價(jià)的,用 cacheNames 或者 value 來指定緩存名。

  • allEntries:一個(gè)布爾值,默認(rèn)為 false。如果設(shè)置為 true,則表示刪除指定緩存中的所有條目。若為 false,則根據(jù) key 屬性(如果沒有提供 key,則默認(rèn)為空)來決定刪除哪個(gè)具體的緩存項(xiàng)。在例子中,由于 allEntries = true,所以無論是否有特定的鍵被定義,都會(huì)清空整個(gè) setmealCache 緩存。

  • beforeInvocation:一個(gè)布爾值,默認(rèn)為 false。如果設(shè)置為 true,那么緩存的清除會(huì)在方法調(diào)用之前發(fā)生;否則,在方法成功執(zhí)行之后才會(huì)進(jìn)行清除操作。這有助于處理方法執(zhí)行過程中可能發(fā)生的異常情況,避免不必要的緩存清除。

  • 使用 allEntries = true 會(huì)一次性清除指定緩存中的所有條目,這對于緩存命中率和性能有一定的影響,特別是在緩存非常大的情況下。因此,應(yīng)該謹(jǐn)慎使用,并確保這是必要的操作。

不是所有 Redis 的功能都可以通過 Spring Cache 注解實(shí)現(xiàn)。

?Spring Cache 注解能做什么?

Spring Cache 的設(shè)計(jì)初衷是簡化緩存操作,提供一種統(tǒng)一的、聲明式的緩存管理方式,適用于常見的緩存場景,比如:

  • 緩存方法結(jié)果(@Cacheable
  • 更新緩存(@CachePut
  • 刪除緩存(@CacheEvict
  • 組合多個(gè)緩存操作(@Caching

這些注解非常適合用于:

  • 讀多寫少的業(yè)務(wù)場景(如查詢接口)
  • 需要緩存方法返回值的場景
  • 避免重復(fù)執(zhí)行耗時(shí)操作(如數(shù)據(jù)庫查詢)

?Spring Cache 注解不能做什么?

雖然 Spring Cache 很方便,但它是一個(gè)抽象層,只封裝了緩存操作中最常見的部分。它并不能覆蓋 Redis 所有的強(qiáng)大功能。以下是一些 Spring Cache 注解無法實(shí)現(xiàn)難以實(shí)現(xiàn)的功能:

Redis 功能Spring Cache 注解是否支持
字符串、哈希、列表、集合、有序集合等數(shù)據(jù)結(jié)構(gòu)操作? 不支持,需使用 RedisTemplateStringRedisTemplate
發(fā)布/訂閱消息(Pub/Sub)? 不支持
Lua 腳本執(zhí)行? 不支持
分布式鎖(SETNX / RedLock)? 不支持
HyperLogLog、Geo、Bitmap 等高級數(shù)據(jù)結(jié)構(gòu)? 不支持
批量操作(Pipeline)? 不支持
事務(wù)(MULTI / EXEC)? 不支持
TTL、KEYS、SCAN 等管理命令? 不支持
自定義緩存過期策略(比如不同 key 有不同的 TTL)?? 部分支持,但不夠靈活

???舉個(gè)例子:

場景:緩存用戶信息

@Cacheable("user")
public User getUserById(Long id) {
    return userRepository.findById(id);
}

? 適合用 Spring Cache,因?yàn)檫@是個(gè)典型的“查數(shù)據(jù)庫緩存結(jié)果”的場景。

場景:實(shí)現(xiàn)一個(gè)分布式鎖

Boolean success = redisTemplate.opsForValue().setIfAbsent("lock_key", "locked", 30, TimeUnit.SECONDS);

? 無法用 Spring Cache 實(shí)現(xiàn),必須用 RedisTemplate 直接操作 Redis。

?什么時(shí)候用 Spring Cache?

  • 你只需要緩存方法的返回值。
  • 你希望代碼更簡潔,不想寫大量緩存邏輯。
  • 你希望統(tǒng)一管理緩存策略(如過期時(shí)間、緩存名稱)。
  • 你未來可能更換緩存實(shí)現(xiàn)(比如從 Redis 換成 Caffeine)。

?什么時(shí)候要直接使用 RedisTemplate?

  • 你需要使用 Redis 的高級功能(如 Hash、List、Pub/Sub、Lua、分布式鎖等)。
  • 你需要更細(xì)粒度地控制 Redis 操作(如 Pipeline、事務(wù))。
  • 你需要實(shí)現(xiàn)一些緩存抽象層無法覆蓋的特殊邏輯。

?最佳實(shí)踐:結(jié)合使用

在實(shí)際項(xiàng)目中,推薦結(jié)合使用 Spring Cache 和 RedisTemplate

  • 對于通用的緩存需求(如方法結(jié)果緩存),使用 Spring Cache 注解。
  • 對于需要 Redis 高級特性的場景,使用 RedisTemplate 直接操作 Redis。

?? 總結(jié)一句話:

Spring Cache 注解只能覆蓋 Redis 的部分緩存功能,不能替代 Redis 的全部能力。
對于復(fù)雜的 Redis 操作,仍需使用 RedisTemplate。

如果正在開發(fā)一個(gè)中大型項(xiàng)目,建議:

  • 對通用緩存邏輯使用 Spring Cache 注解;
  • 對 Redis 高級功能單獨(dú)封裝成 Redis 工具類或服務(wù)類,使用 RedisTemplate 來實(shí)現(xiàn)。

這樣既能享受注解帶來的便捷,又能保留 Redis 的靈活性和強(qiáng)大功能。

1. 字符串、哈希、列表、集合、有序集合等數(shù)據(jù)結(jié)構(gòu)操作

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 主要用于緩存方法的結(jié)果,并不直接支持對 Redis 的各種數(shù)據(jù)類型(如字符串、哈希、列表、集合和有序集合)的操作。

解決方案:
使用 RedisTemplateStringRedisTemplate 來進(jìn)行更復(fù)雜的 Redis 數(shù)據(jù)類型操作。

示例:字符串操作

@Autowired
private StringRedisTemplate stringRedisTemplate;
public void stringOperationsExample(String key, String value) {
    // 設(shè)置字符串值
    stringRedisTemplate.opsForValue().set(key, value);
    // 獲取字符串值
    String retrievedValue = stringRedisTemplate.opsForValue().get(key);
    System.out.println("Retrieved Value: " + retrievedValue);
}

示例:哈希操作

public void hashOperationsExample(String key, String field, String value) {
    // 設(shè)置哈希表中的字段值
    stringRedisTemplate.opsForHash().put(key, field, value);
    // 獲取哈希表中字段的值
    Object fieldValue = stringRedisTemplate.opsForHash().get(key, field);
    System.out.println("Field Value: " + fieldValue);
}

示例:列表操作

public void listOperationsExample(String key, String... values) {
    // 右側(cè)插入元素到列表
    for (String value : values) {
        stringRedisTemplate.opsForList().rightPush(key, value);
    }
    
    // 獲取列表中的所有元素
    List<String> elements = stringRedisTemplate.opsForList().range(key, 0, -1);
    
    System.out.println("List Elements: " + elements);
}

示例:集合操作

public void setOperationsExample(String key, String... members) {
    // 添加成員到集合
    for (String member : members) {
        stringRedisTemplate.opsForSet().add(key, member);
    }
    // 獲取集合中的所有成員
    Set<String> membersSet = stringRedisTemplate.opsForSet().members(key);
    System.out.println("Members of Set: " + membersSet);
}

示例:有序集合操作

public void sortedSetOperationsExample(String key, String member, double score) {
    // 添加成員到有序集合并指定分?jǐn)?shù)
    stringRedisTemplate.opsForZSet().add(key, member, score);
    // 獲取有序集合中的所有成員及其分?jǐn)?shù)
    Set<ZSetOperations.TypedTuple<String>> tuples = stringRedisTemplate.opsForZSet().rangeWithScores(key, 0, -1);
    tuples.forEach(tuple -> System.out.println("Member: " + tuple.getValue() + ", Score: " + tuple.getScore()));
}

2. 發(fā)布/訂閱消息(Pub/Sub)

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 不支持發(fā)布/訂閱模式。

解決方案:
使用 RedisTemplate 進(jìn)行發(fā)布/訂閱操作。

@Autowired
private StringRedisTemplate stringRedisTemplate;
// 訂閱者
public void subscribeToChannel(String channelName) {
    stringRedisTemplate.getConnectionFactory().getConnection().subscribe((message, pattern) -> {
        System.out.println("Received message on channel [" + new String(pattern) + "] with content: " + new String(message.getBody()));
    }, channelName.getBytes());
}
// 發(fā)布者
public void publishToChannel(String channelName, String message) {
    stringRedisTemplate.convertAndSend(channelName, message);
}

3. Lua 腳本執(zhí)行

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 不支持執(zhí)行 Lua 腳本。

解決方案:
使用 RedisTemplate 執(zhí)行 Lua 腳本。

@Autowired
private StringRedisTemplate stringRedisTemplate;
public void executeLuaScript() {
    DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
    redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua_script.lua")));
    redisScript.setResultType(Long.class);
    List<String> keys = Arrays.asList("key1", "key2");
    Long result = stringRedisTemplate.execute(redisScript, keys, "arg1");
    System.out.println("Lua Script Result: " + result);
}

4. 分布式鎖(SETNX / RedLock)

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 不支持分布式鎖機(jī)制。

解決方案:
使用 RedisTemplate 實(shí)現(xiàn)分布式鎖。

@Autowired
private StringRedisTemplate stringRedisTemplate;
public boolean acquireLock(String lockKey, long timeout) throws InterruptedException {
    long millisecondsTimeout = System.currentTimeMillis() + timeout;
    while (System.currentTimeMillis() < millisecondsTimeout) {
        Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "locked", Duration.ofMinutes(1));
        if (Boolean.TRUE.equals(success)) {
            return true;
        }
        Thread.sleep(100); // 等待一段時(shí)間后重試
    }
    return false;
}
public void releaseLock(String lockKey) {
    stringRedisTemplate.delete(lockKey);
}

5. HyperLogLog、Geo、Bitmap 等高級數(shù)據(jù)結(jié)構(gòu)

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 不支持這些高級數(shù)據(jù)結(jié)構(gòu)。

解決方案:
使用 RedisTemplate 操作這些高級數(shù)據(jù)結(jié)構(gòu)。

Geo 操作示例:

public void geoOperationsExample() {
    stringRedisTemplate.opsForGeo().add("cities",
        new Point(13.361389, 38.115556), "Palermo",
        new Point(15.087269, 37.502669), "Catania");
    Distance distance = stringRedisTemplate.opsForGeo().distance("cities", "Palermo", "Catania", RedisGeoCommands.DistanceUnit.KILOMETERS);
    System.out.println("Distance between Palermo and Catania: " + distance.getValue() + " km");
}

6. 批量操作(Pipeline)

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 不支持批量操作。

解決方案:
使用 RedisTemplate 進(jìn)行批量操作。

public void pipelineOperationsExample() {
    List<Object> results = stringRedisTemplate.executePipelined((RedisCallback<String>) connection -> {
        connection.openPipeline();
        connection.set("key1".getBytes(), "value1".getBytes());
        connection.incr("key2".getBytes());
        return null;
    });
    System.out.println("Pipeline Results: " + results);
}

7. 事務(wù)(MULTI / EXEC)

Spring Cache 注解的支持情況:

  • 不支持。Spring Cache 不支持事務(wù)操作。

解決方案:
使用 RedisTemplate 進(jìn)行事務(wù)操作。

public void transactionOperationsExample() {
    stringRedisTemplate.execute(new SessionCallback<List<Object>>() {
        @Override
        public List<Object> execute(RedisOperations operations) throws DataAccessException {
            operations.multi();
            operations.opsForValue().increment("key1");
            operations.opsForValue().increment("key2");
            return operations.exec(); // 執(zhí)行并返回結(jié)果
        }
    });
}

8. TTL、KEYS、SCAN 等管理命令

Spring Cache 注解的支持情況:

  • 部分支持。雖然可以設(shè)置全局的 TTL,但不能為每個(gè)鍵單獨(dú)設(shè)置不同的 TTL。

解決方案:
使用 RedisTemplate 設(shè)置 TTL 和執(zhí)行其他管理命令。

public void ttlOperationsExample(String key) {
    // 設(shè)置TTL
    stringRedisTemplate.expire(key, Duration.ofMinutes(10));
}
public void scanKeysExample() {
    ScanOptions options = ScanOptions.scanOptions().match("*").count(100).build();
    Cursor<Map.Entry<byte[], byte[]>> cursor = stringRedisTemplate.executeWithStickyConnection(
        redisConnection -> new ConvertingCursor<>(redisConnection.scan(options),
            entry -> new AbstractMap.SimpleEntry<>(new String(entry.getKey()), new String(entry.getValue()))));
    while (cursor.hasNext()) {
        Map.Entry<String, String> entry = cursor.next();
        System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
    }
}

通過上述例子可以看出,雖然 Spring Cache 提供了便捷的方式來管理緩存,但對于 Redis 的復(fù)雜功能,需要依賴 RedisTemplateStringRedisTemplate 來實(shí)現(xiàn)。這種方式不僅保留了 Redis 的靈活性,同時(shí)也使得開發(fā)者能夠充分利用 Redis 的強(qiáng)大功能。

到此這篇關(guān)于sky-take-out項(xiàng)目中Redis的使用的文章就介紹到這了,更多相關(guān)sky-take-out redis使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Web導(dǎo)出等比例圖片到Excel的實(shí)現(xiàn)過程

    Java Web導(dǎo)出等比例圖片到Excel的實(shí)現(xiàn)過程

    我們使用Java導(dǎo)出圖片到Excel,打開成功導(dǎo)出的Excel一看,商品對應(yīng)的圖片都很規(guī)矩的按照我的設(shè)置鋪滿了整個(gè)單元格,但是,商品圖片卻都變形了,這樣肯定是不行的,于是第一反應(yīng)就是將圖片等比例導(dǎo)出,所以本文本給大家介紹了如何使用Java Web導(dǎo)出等比例圖片到Excel
    2023-11-11
  • java 抽象類和接口的區(qū)別詳細(xì)解析

    java 抽象類和接口的區(qū)別詳細(xì)解析

    abstractclass和interface是Java語言中對于抽象類定義進(jìn)行支持的兩種機(jī)制,正是由于這兩種機(jī)制的存在,才賦予了Java強(qiáng)大的面向?qū)ο竽芰?需要了解的朋友可以參考下
    2012-11-11
  • 詳解Springboot對多線程的支持

    詳解Springboot對多線程的支持

    Spring是通過任務(wù)執(zhí)行器(TaskExecutor)來實(shí)現(xiàn)多線程和并發(fā)編程,使用ThreadPoolTaskExecutor來創(chuàng)建一個(gè)基于線城池的TaskExecutor。這篇文章給大家介紹Springboot對多線程的支持,感興趣的朋友一起看看吧
    2018-07-07
  • Java簡單高效實(shí)現(xiàn)分頁功能

    Java簡單高效實(shí)現(xiàn)分頁功能

    這篇文章主要介紹了Java簡單高效實(shí)現(xiàn)分頁功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 關(guān)于解決iReport4.1.1無法正常啟動(dòng)或者閃退或者JDK8不兼容的問題

    關(guān)于解決iReport4.1.1無法正常啟動(dòng)或者閃退或者JDK8不兼容的問題

    在安裝使用iReport的過程中遇到一個(gè)問題,我的iReport始終不能打開,困擾了我好久。接下來通過本文給大家介紹iReport4.1.1無法正常啟動(dòng)或者閃退或者JDK8不兼容的問題,需要的朋友可以參考下
    2018-09-09
  • Java?超詳細(xì)講解十大排序算法面試無憂

    Java?超詳細(xì)講解十大排序算法面試無憂

    這篇文章主要介紹了Java常用的排序算法及代碼實(shí)現(xiàn),在Java開發(fā)中,對排序的應(yīng)用需要熟練的掌握,這樣才能夠確保Java學(xué)習(xí)時(shí)候能夠有扎實(shí)的基礎(chǔ)能力。那Java有哪些排序算法呢?本文小編就來詳細(xì)說說Java常見的排序算法,需要的朋友可以參考一下
    2022-04-04
  • java聯(lián)調(diào)生成測試數(shù)據(jù)工具類方式

    java聯(lián)調(diào)生成測試數(shù)據(jù)工具類方式

    這篇文章主要介紹了java聯(lián)調(diào)生成測試數(shù)據(jù)工具類方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • druid?handleException執(zhí)行流程源碼解析

    druid?handleException執(zhí)行流程源碼解析

    這篇文章主要為大家介紹了druid?handleException執(zhí)行流程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • SpringBoot使用Guava實(shí)現(xiàn)日志脫敏的示例代碼

    SpringBoot使用Guava實(shí)現(xiàn)日志脫敏的示例代碼

    本文主要介紹了SpringBoot使用Guava實(shí)現(xiàn)日志脫敏的示例代碼,使用Guava中的Strings、Maps和CharMatcher類來進(jìn)行日志脫敏,保護(hù)敏感數(shù)據(jù)的安全,感興趣的可以了解一下
    2024-01-01
  • Java?-jar命令如何運(yùn)行外部依賴JAR包

    Java?-jar命令如何運(yùn)行外部依賴JAR包

    在Java應(yīng)用部署中,java?-jar命令是啟動(dòng)可執(zhí)行JAR包的標(biāo)準(zhǔn)方式,但當(dāng)應(yīng)用需要依賴外部JAR文件時(shí),直接使用java?-jar會(huì)面臨類加載困境,本文就來聊聊該如何解決吧
    2025-06-06

最新評論

泰兴市| 雅江县| 商丘市| 德保县| 佳木斯市| 嘉兴市| 古田县| 滨州市| 丹巴县| 常山县| 凉城县| 棋牌| 攀枝花市| 中超| 九龙坡区| 三明市| 屯留县| 万源市| 文成县| 靖远县| 嵩明县| 和林格尔县| 罗甸县| 万荣县| 攀枝花市| 朝阳市| 靖安县| 安宁市| 屯留县| 汉源县| 芒康县| 大同市| 舒兰市| 南昌市| 建阳市| 蕲春县| 白沙| 张掖市| 福海县| 延庆县| 新田县|