python redis事务_redis事务

本文记录一些redis事务相关的原理。

1、基本概念

1)什么是redis的事务?

简单理解,可以认为redis事务是一些列redis命令的集合,并且有如下两个特点:

a)事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

b)事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

2)事务的性质ACID

一般来说,事务有四个性质称为ACID,分别是原子性,一致性,隔离性和持久性。

a)原子性atomicity:redis事务保证事务中的命令要么全部执行要不全部不执行。有些文章认为redis事务对于执行错误不回滚违背了原子性,是偏颇的。

b)一致性consistency:redis事务可以保证命令失败的情况下得以回滚,数据能恢复到没有执行之前的样子,是保证一致性的,除非redis进程意外终结。

c)隔离性Isolation:redis事务是严格遵守隔离性的,原因是redis是单进程单线程模式,可以保证命令执行过程中不会被其他客户端命令打断。

d)持久性Durability:redis事务是不保证持久性的,这是因为redis持久化策略中不管是RDB还是AOF都是异步执行的,不保证持久性是出于对性能的考虑。

3)redis事务的错误

使用事务时可能会遇上以下两种错误:

a)入队错误:事务在执行 EXEC 之前,入队的命令可能会出错。比如说,命令可能会产生语法错误(参数数量错误,参数名错误,等等),或者其他更严重的错误,比如内存不足(如果服务器使用 maxmemory 设置了最大内存限制的话)。

b)执行错误:命令可能在 EXEC 调用之后失败。举个例子,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。

注:第三种错误,redis进程终结,本文并没有讨论这种错误。

2、redis事务的用法

redis事务是通过MULTI,EXEC,DISCARD和WATCH四个原语实现的。

MULTI命令用于开启一个事务,它总是返回OK。

MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。

另一方面,通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务。

下面给出几种事务场景。

1)正常执行

127.0.0.1:6379>MULTI

OK127.0.0.1:6379> SET key1 1QUEUED127.0.0.1:6379> HSET key2 field1 1QUEUED127.0.0.1:6379> SADD key3 1QUEUED127.0.0.1:6379>EXEC1) OK2) (integer) 1

3) (integer) 1

EXEC 命令的回复是一个数组,数组中的每个元素都是执行事务中的命令所产生的回复。 其中,回复元素的先后顺序和命令发送的先后顺序一致。

当客户端处于事务状态时,所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply),这些被入队的命令将在 EXEC命令被调用时执行。

2)放弃事务

当执行 DISCARD 命令时,事务会被放弃,事务队列会被清空,并且客户端会从事务状态中退出:

127.0.0.1:6379>MULTI

OK127.0.0.1:6379> SET key1 1QUEUED127.0.0.1:6379>DISCARD

OK127.0.0.1:6379>EXEC

(error) ERR EXEC without MULTI

3)入队错误回滚

127.0.0.1:6379>MULTI

OK127.0.0.1:6379> set key1 1QUEUED127.0.0.1:6379> HSET key2 1(error) ERR wrong number of argumentsfor 'hset'command127.0.0.1:6379> SADD key3 1QUEUED127.0.0.1:6379>EXEC

(error) EXECABORT Transaction discarded because of previous errors.

对于入队错误,redis 2.6.5版本后,会记录这种错误,并且在执行EXEC的时候,报错并回滚事务中所有的命令,并且终止事务。

3)执行错误放过

127.0.0.1:6379>MULTI

OK127.0.0.1:6379> HSET key1 field1 1QUEUED127.0.0.1:6379> HSET key2 field1 1QUEUED127.0.0.1:6379>EXEC1) (error) WRONGTYPE Operation against a key holding the wrong kind of value2) (integer) 1

当遇到执行错误时,redis放过这种错误,保证事务执行完成。

这里要注意此问题,与mysql中事务不同,在redis事务遇到执行错误的时候,不会进行回滚,而是简单的放过了,并保证其他的命令正常执行。这个区别在实现业务的时候,需要自己保证逻辑符合预期。

3、使用WATCH

WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。

被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回空多条批量回复(null multi-bulk reply)来表示事务已经失败。

127.0.0.1:6379>WATCH key1

OK127.0.0.1:6379> set key1 2OK127.0.0.1:6379>MULTI

OK127.0.0.1:6379> set key1 3QUEUED127.0.0.1:6379> set key2 3QUEUED127.0.0.1:6379>EXEC

(nil)

使用上面的代码, 如果在 WATCH 执行之后, EXEC 执行之前, 有其他客户端修改了 key1 的值, 那么当前客户端的事务就会失败。 程序需要做的, 就是不断重试这个操作, 直到没有发生碰撞为止。

这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。 并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。

4、python实现redis事务的demo

这里展示一个用python实现对key计数减一的原子操作。

#-*- coding:utf-8 -*-

importredisfrom redis importWatchErrorfrom concurrent.futures importProcessPoolExecutor

r= redis.Redis(host='127.0.0.1', port=6379)#减库存函数, 循环直到减库存完成#库存充足, 减库存成功, 返回True#库存不足, 减库存失败, 返回False

defdecr_stock():#python中redis事务是通过pipeline的封装实现的

with r.pipeline() as pipe:whileTrue:try:#watch库存键, multi后如果该key被其他客户端改变, 事务操作会抛出WatchError异常

pipe.watch('stock:count')

count= int(pipe.get('stock:count'))if count > 0: #有库存

#事务开始

pipe.multi()

pipe.decr('stock:count')#把命令推送过去

#execute返回命令执行结果列表, 这里只有一个decr返回当前值

printpipe.execute()[0]returnTrueelse:returnFalseexceptWatchError, ex:#打印WatchError异常, 观察被watch锁住的情况

printex

pipe.unwatch()defworker():whileTrue:#没有库存就退出

if notdecr_stock():break

#实验开始#设置库存为100

r.set("stock:count", 100)#多进程模拟多个客户端提交

with ProcessPoolExecutor(max_workers=2) as pool:for _ in range(10):

pool.submit(worker)

观察打印

/Users/didi/anaconda/bin/python /Users/didi/test/pythoneer/redis/transaction.py99

98

97Watched variable changed.96

95

94

93Watched variable changed.92Watched variable changed.91Watched variable changed.90Watched variable changed.89Watched variable changed.88Watched variable changed.

Watched variable changed.87

86Watched variable changed.85Watched variable changed.84Watched variable changed.

Watched variable changed.83

82Watched variable changed.81Watched variable changed.

Watched variable changed.80

79Watched variable changed.

Watched variable changed.78

77Watched variable changed.

Watched variable changed.76

75Watched variable changed.

Watched variable changed.74Watched variable changed.73

72Watched variable changed.

Watched variable changed.71

70Watched variable changed.69Watched variable changed.68Watched variable changed.67Watched variable changed.66Watched variable changed.

Watched variable changed.65

64Watched variable changed.63Watched variable changed.

Watched variable changed.62Watched variable changed.61

60Watched variable changed.59Watched variable changed.

Watched variable changed.58

57Watched variable changed.

Watched variable changed.56Watched variable changed.55

54Watched variable changed.53Watched variable changed.52Watched variable changed.

Watched variable changed.51

50Watched variable changed.49Watched variable changed.48Watched variable changed.47Watched variable changed.

Watched variable changed.46Watched variable changed.45Watched variable changed.44

43Watched variable changed.42Watched variable changed.

Watched variable changed.41

40Watched variable changed.

Watched variable changed.39Watched variable changed.38Watched variable changed.37Watched variable changed.36Watched variable changed.35

34Watched variable changed.33Watched variable changed.

Watched variable changed.32Watched variable changed.31

30Watched variable changed.

Watched variable changed.29Watched variable changed.28Watched variable changed.27

26Watched variable changed.25Watched variable changed.24Watched variable changed.23Watched variable changed.

22Watched variable changed.

Watched variable changed.2120Watched variable changed.19Watched variable changed.18Watched variable changed.17Watched variable changed.16Watched variable changed.

Watched variable changed.15Watched variable changed.14Watched variable changed.13

12Watched variable changed.

Watched variable changed.11Watched variable changed.10Watched variable changed.9

8Watched variable changed.7Watched variable changed.

Watched variable changed.6

5Watched variable changed.

Watched variable changed.4Watched variable changed.3

2Watched variable changed.1Watched variable changed.

0

Watched variable changed.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值