iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0

常用指令

String 是最單純的型別,一個 key 對一個值。

  • SET key value
    https://ithelp.ithome.com.tw/upload/images/20260916/20184209I7AFj5kv0Z.png

  • GET key
    https://ithelp.ithome.com.tw/upload/images/20260917/20184209biwjpsl3mF.png

  • MGET key ...(一次取多個)
    https://ithelp.ithome.com.tw/upload/images/20260916/20184209jC2tMG5PuC.png

  • SETEX key TTL value(存的同時設定過期時間,預設秒)
    https://ithelp.ithome.com.tw/upload/images/20260916/20184209MPpOeCrsGX.png

  • TTL key(查看剩餘時間,-1 永久保存,-2 key不存在,已過期)
    https://ithelp.ithome.com.tw/upload/images/20260916/20184209OQZcpD4XBp.png

  • SETNX key value(0 是已存在,不覆蓋,1 是儲存成功)
    https://ithelp.ithome.com.tw/upload/images/20260916/20184209xycqFVP8B1.png

  • INCR key(原子 + 1)
    https://ithelp.ithome.com.tw/upload/images/20260916/20184209OlvJpqH9kD.png

  • INCRBY key num(一次增加指定的數值 num)
    https://ithelp.ithome.com.tw/upload/images/20260917/20184209TF8CB60o7E.png

  • DECR key(原子 - 1)
    https://ithelp.ithome.com.tw/upload/images/20260917/201842090Mow6A5MKX.png

  • DECRBY key num(一次減少指定的數值 num)
    https://ithelp.ithome.com.tw/upload/images/20260917/20184209ORvPnc9ygp.png

SETNX 「已經存在就不動」的特性,之後做分散式鎖會用到。

存物件進去

Day 2 留了一個坑:同樣的程式碼換成 RedisTemplate,在 redis-cli 看到的會是這種東西。

"\xac\xed\x00\x05t\x00\x0bhello-redis"

因為 RedisTemplate 預設用 Java 序列化,存進去是二進位,只有 Java 讀得懂。

解法很單純:不要用它,自己把物件轉成 JSON 字串,繼續用 Day 2 的 StringRedisTemplate 就好。

商品快取

最常被拿來做快取,先查 Redis,沒有才去資料庫撈,撈完順手寫回快取。

@GetMapping("/{id}")
public Map<String, Object> get(@PathVariable Long id) throws JsonProcessingException {
    String key = "product:" + id;

    String json = redis.opsForValue().get(key);
    if (json != null) {
        return result(mapper.readValue(json, Product.class), "HIT");
    }

    Product product = loadFromDb(id); // sleep 100 毫秒,模擬查詢成本 
    
    redis.opsForValue().set(key, mapper.writeValueAsString(product), TTL); // 給 TTL
    
    return result(product, "MISS");
}

mapper 就是 Spring Boot 準備好的 ObjectMapper,直接注入,不用自己設定。

curl http://localhost:8080/product/1001
https://ithelp.ithome.com.tw/upload/images/20260917/20184209FMfOFnyx93.png

curl http://localhost:8080/product/1001
https://ithelp.ithome.com.tw/upload/images/20260917/20184209UXJ9K1Novu.png

108 毫秒變成 2 毫秒。有快取到真的變超快,每個快取 key 都要設 TTL,不然那筆資料會一直佔著記憶體!

計數器

Redis 沒有數字型別,計數器就是存數字的 String。

Day 3 說單執行緒讓每個指令天然是原子的,實際打一次看看。

private int javaCount = 0;   // 故意不用 AtomicInteger

@GetMapping("/java")
public int java() {
    return ++javaCount;
}

@GetMapping("/redis")
public Long redis() {
    return redis.opsForValue().increment("counter:redis");
}

用 k6 開 50 個虛擬使用者,兩邊各打 5000 次:

export const options = {
  vus: 50,          // 50 個虛擬使用者同時打
  iterations: 5000, // 總共各打 5000 次
};

export default function () {
  http.get('http://localhost:8080/counter/java');
  http.get('http://localhost:8080/counter/redis');
}

https://ithelp.ithome.com.tw/upload/images/20260917/20184209WZHjWeGQMT.png

Redis 準準的 5000,Java 少了 47 次。

因為 ++ 其實是「讀 → 加 → 寫回」三個動作,兩條執行緒同時讀到 100,就會各自寫回 101,少加一次。這叫 lost update。

Java 要修得靠 AtomicIntegersynchronized,Redis 什麼都不用做。

相關範例程式碼可以參考 https://github.com/gary880306/redis-30days/tree/dev

明天

商品快取是整包存、整包讀。明天換成購物車,只改其中一件的數量試試看!


上一篇
Day 3|Redis 為什麼快?
下一篇
Day 5|購物車:String 還是 Hash?
系列文
從購物車到秒殺:30 天 Redis 高併發自學筆記5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言