@@ -66,7 +66,7 @@ class Cache:
6666 return self .client.get(key)
6767
6868 def update (self , new_value , key ):
69- return self .client.getset(key, new_value)
69+ return self .client.getset(key, new_value) # 设置新值, 返回旧值
7070
7171```
7272
@@ -295,7 +295,7 @@ class Article:
295295- APPEND: 追加新内容到值的末尾
296296> APPEND key suffix
297297
298- 若用户给定的 key 不存在, 则会先将键执行追加操作
298+ 若用户给定的 key 不存在, 则相当于 SET key suffix
299299
300300
301301### 示例: 存储日志
@@ -326,10 +326,130 @@ class Log:
326326```
327327
328328
329- ----------
330-
329+ ## 数字值
331330下面介绍使用字符串键存储数字值:
332331
333332每当存储一个值到字符串键里面的时候, 有下面两种情况
3343331 . C 语言 long long int 类型的整数, 取值范围为 -2^63 ~ 2^63-1 (超出范围会被当成字符串)
3353342 . C 语言 long double 类型的浮点数
335+
336+ 为了方便地处理字符串键的值, Redis 提供了一系列加法和减法操作命令, 下面介绍这些命令
337+
338+ - INCRBY, DECRBY: 对整数执行加法和减法操作 O(1)
339+ > INCRBY key increment
340+ > DECRBY key increment
341+
342+ 如果类型为浮点数, 使用上面方法会报错 (key的值 和 increment 都必须为整数)
343+
344+ 当该命令遇到**不存在的键**时, 会将键的值初始化为0, 然后再执行操作
345+
346+ - INCR, DECR: 对整数执行加1和减1操作 O(1)
347+ > INCR key
348+ > DECR key
349+
350+ - INCRBYFLOAT: 对数字值执行浮点数加减法操作
351+ > INCRBYFLOAT key increment
352+
353+ INCRBYFLOAT 命令即执行加法操作, 也可以执行加法操作, 并且操作对象和 increment 都既可以为整数也可以为浮点数
354+
355+ 虽然 Redis 没有限制字符串键存储浮点数的小数位数, 但是 INCRBYFLOAT 最多只会保留小数点后的17位数字, 超出部分将被截断
356+
357+ ### 示例: ID 生成器
358+ identifier 标识符, 经常在程序中使用, 通常以数字形式出现, 并通过递增的方法创建新的ID.
359+
360+ ``` Python
361+ from redis import Redis
362+
363+ class IdGenerator :
364+ def __init__ (self , client , key ):
365+ self .client = client
366+ self .key = key
367+ def produce (self ):
368+ """ 生成下一个id"""
369+ return self .client.incr(self .key)
370+ def reserve (self , n ):
371+ """ 初始化"""
372+ result = self .client.set(self .key, n, nx = 1 ) # key 不存在才行
373+ return result is True
374+
375+ client = Redis(decode_responses = True )
376+ id_generator = IdGenerator(client, " user::id" )
377+ print (id_generator.reserve(1000000 )) # 保留100万个ID -> True
378+ print (id_generator.produce()) # 生成ID, 均大于100万
379+
380+ print (id_generator.reserve(1000 )) # 已存在 -> False
381+ ```
382+
383+ ### 示例: 计数器
384+ 除了ID生成器, 计数器也是常用的组件之一, 例如点赞回复数量, 播放量等.
385+ ``` Python
386+ from redis import Redis
387+
388+ class Counter :
389+ def __init__ (self , client , key ):
390+ self .client = client
391+ self .key = key
392+ def increase (self , n = 1 ):
393+ return self .client.incr(self .key, n)
394+ def decrease (self , n = 1 ):
395+ return self .client.decr(self .key, n)
396+ def get (self ):
397+ value = self .client.get(self .key)
398+ if value in None :
399+ return 0
400+ else :
401+ return int (value)
402+ def reset (self ):
403+ old_value = self .client.getset(self .key)
404+ if old_value is None :
405+ return 0
406+ else :
407+ return (old_value)
408+
409+ client = Redis(decode_responses = True )
410+ counter = Counter(client, " counter::page_viewed" )
411+
412+ print (counter.increase()) # +1
413+ print (counter.increase())
414+ print (counter.increase(10 )) # +10
415+
416+ print (counter.decrease()) # -1
417+ print (counter.decrease(5 )) # -5
418+
419+ print (counter.reset()) # 重置计数器
420+ print (counter.get()) # 返回计数器当前值
421+ ```
422+ > 注: 在 redis-py 中 INCR 和 INCRBY 都使用 .incr() 方法
423+
424+
425+ ### 示例: 限速器
426+ 为了保障系统的安全性和性能, 并保证重要资源不被滥用, 应用程序需要对用户的行为进行限制
427+ - 防止网络爬虫: 限制每个IP地址在固定时间段内访问的页面数量
428+ - 防止爆力破解: 当用户多次输入错误的密码, 会帐号进行冻结
429+
430+ 上面机制的实现可以使用限速器, 下面是一个限速器示例代码, 该程序将操作最大可执行次数存储在一个字符串里面, 每次用户进行该操作后就将其减1
431+ ``` Python
432+ from redis import Redis
433+
434+ class Limter :
435+ def __init__ (self , client , key ):
436+ self .client = client
437+ self .key = key
438+ def set_max_execute_times (self , max_execut_time ):
439+ self .client.set(self .key, max_execut_time)
440+ def still_valid_to_execute (self ):
441+ num = self .client.decr(self .key)
442+ return (num >= 0 )
443+ def remaining_execute_times (self ):
444+ num = int (self .client.get(self .key))
445+ if num < 0 :
446+ return 0
447+ else :
448+ return num
449+
450+ client = Redis(decode_responses = True )
451+ limter = Limter(client, " wrong_password_limter" )
452+
453+ print (limter.set_max_execute_times(5 )) # 最多5次输入错误密码
454+ print (limter.still_valid_to_execute()) # 前5次 True, 之后 False
455+ ```
0 commit comments