Python实现redis的自增操作

在传统的数据库中, 如果实现一个计数器的操作, 需要先去数据库中读取该值, 再程序中加1, 再讲最新的值存入数据库. 用户操作的流程步骤多不说, 还容易出现数据安全性的问题, 比如多进程/多线程的并发情况, 有可能出现A进程读取的计数器为5, 在本地执行+1, 操作的时候, 此时B进程也去执行计数器+1操作, B读取的数值也是5, 然后A将+1之后的数字6存入数据库, 之后B处理完后也将+1之后的6存入数据库, 这样就导致了在并发的情况下, 计数器的数据不准的情况.

Redis的很多操作本身都是原子性的, 例如上面案例中, 计数器+1的问题, 会有三个步骤

  • 读取数值
  • 自增操作
  • 写入数值

在传统数据库中, 为了保证数据的安全性, 这三个步骤通常是要加锁的, 也就是在步骤已经很多的情况下, 还需要考虑锁的问题. 但是Redis就不同了, Redis原子性的意思就是说, 可以保证上面的三个步骤是一个操作, 在这个操作完成之后才允许我们对其进行其他操作, 这就原生的保证了数据安全性

redis中的自增

在redis中, 如果一个key的value是数值类型, 我们就可以对这个值进行incr操作, 如果数值是整形int, 使用incr进行自增操作, 如果数值是浮点型float, 则需要使用incrbyfloat进行操作, 还有一种情况, 就是对int使用了incrbyfloat操作, 则这个数值就会变成float类型, 也就无法再对其执行incr操作了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
In [1]: import redis

In [2]: pool=redis.ConnectionPool(host='127.0.0.1',port=6379,db=0)

In [3]: r = redis.StrictRedis(connection_pool=pool)

In [4]: r.keys()
Out[4]: []

In [5]: r.incr('counter')
Out[5]: 1

In [6]: r.incr('counter')
Out[6]: 2

In [7]: r.incr('counter')
Out[7]: 3

In [8]: r.incr('counter', 2)
Out[8]: 5

In [9]: r.keys()
Out[9]: [b'counter']

In [10]: r.get('counter')
Out[10]: b'5'

In [11]: r.incrbyfloat('counter')
Out[11]: 6.0

In [12]: r.incrbyfloat('counter')
Out[12]: 7.0

In [13]: r.incrbyfloat('counter', 0.1)
Out[13]: 7.1

In [14]: r.incrbyfloat('counter', 0.1)
Out[14]: 7.2

redis中的自减

redis中使用decr函数进行自减操作, 但是自减中, 没有提供类似incrbyfloat的操作, 如果在自减中想实现浮点数的效果, 可以通过在incrbyfloat函数中使用负数的方式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [19]: r.keys()
Out[19]: []

In [20]: r.incr('counter')
Out[20]: 1

In [21]: r.decr('counter')
Out[21]: 0

In [22]: r.incrbyfloat('counter', -1.1)
Out[22]: -1.1

In [23]: r.incrbyfloat('counter', -1.1)
Out[23]: -2.2