redis系列之--事务

本文探讨了Redis中的事务特性,包括MULTI和EXEC命令的使用,以及事务的ACID属性。尽管Redis不完全支持原子性和持久性,但其隔离性得到保证。此外,介绍了WATCH命令作为乐观锁的实现方式,当数据变动时,事务会自动取消。还提到了setnx命令作为简单悲观锁的替代,并讨论了非事务型管道在Redis中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

redis系列之–事务


语法
  • MULTI
    • 开启事务, 后续的命令会被加入到同一个事务中
    • 事务中的操作会发给服务端, 但是不会立即执行, 而是放到了该事务的对应的一个队列中, 服务端返回QUEUED
  • EXEC
    • 执行EXEC后, 事务中的命令才会被执行
    • 事务中的命令出现错误时, 不会回滚也不会停止事务, 而是继续执行
  • DISCARD
    • 取消事务, 事务队列会清空, 客户端退出事务状态

ACID
  • 原子性
    • 不支持
    • 不会回滚并且继续执行
  • 隔离性
    • 支持
    • 事务中命令顺序执行, 并且不会被其他客户端打断 (先EXEC的先执行)
    • 单机redis读写操作使用单进程单线程
  • 持久性
    • 不支持, redis数据易丢失
  • 一致性
    • 不支持
    • 强一致性要求 通过乐观锁(watch)来实现

  • redis 管道默认开启事务
from redis import StrictRedis

# 创建redis连接
redis_client = StrictRedis(host='127.0.0.1', port=6379, db=0, decode_responses=True)

# 创建管道    默认就会开启事务
pipe = redis_client.pipeline()

# 使用管道对象进行数据操作   事务中的操作不会立即执行, 不会立即返回结果
a = pipe.get('age')
b = pipe.set('age', 30)

# 提交事务  由于管道机制, redis命令会一起打包发送给服务器, 并返回结果
c = pipe.execute()
print(a)
print(b)
print(c)

WATCH
  • redis实现的乐观锁
  • 机制
    • 事务开启前, 设置对数据的监听, EXEC时, 如果发现数据发生过修改, 事务会自动取消(DISCARD)
    • 事务EXEC后, 无论成败, 监听会被移除
WATCH mykey  # 监视mykey的值
MULTI  # 开启事务(手动)
SET mykey 10  
EXEC  # 如果mykey的值在执行exec之前发生过改变, 则该事务会取消(客户端可以在发生碰撞后不断重试)
from redis import StrictRedis, WatchError

# 创建redis连接
redis_client = StrictRedis(host='127.0.0.1', port=6379, db=0, decode_responses=True)

"""使用redis乐观锁实现秒杀超卖需求"""

# 1.创建管道    默认就会开启事务
pipe = redis_client.pipeline()

while True:
    try:
        # 2.监听数据    一旦使用了watch, 则不会自动开启事务, 后续的操作会立即发送给服务器并执行
        pipe.watch('count:reserve')

        # 3.获取数据   可以立即得到结果
        count = pipe.get('count:reserve')

        if int(count) > 0:  #  有库存, 减库存并且生成订单
            # 4. 手动开启事务  开启后, 后续的操作会加入到事务中
            pipe.multi()
            # 减少库存
            pipe.decr('count:reserve')
            # 提交事务  如果监听的数据中途被修改, 会抛出WatchError错误, 可以捕获异常,并重试/取消
            pipe.execute()  # 无论成功失败, 监听都会移除
            print('生成订单')

        else:  # 无库存
            # 手动移除监听
            pipe.reset()
            print("已售罄")
        break

    except WatchError as e:
        # 监听的数据被修改
        print('重试')
        continue


setnx和悲观锁
  • setnx 键不存在,才会设置成功
from redis import StrictRedis

# 创建redis连接
redis_client = StrictRedis(decode_responses=True)

# 设计redis悲观锁/分布式锁 处理秒杀超卖问题

# 先获取锁
while True:
    order_lock = redis_client.setnx('lock:order', 1)
    if order_lock:
        reserve_count = redis_client.get('count:reserve')
        if int(reserve_count) > 0:
            redis_client.decr('count:reserve')
            print("生成订单")
        else:
            print("已售罄")
        # 完成处理, 移除锁
        redis_client.delete('lock:order')
        break

非事务型管道
from redis import StrictRedis

# redis实现了管道机制, 可以将多个操作打包发送给redis服务器
# 可以单独使用管道, 不需要开启事务 对于没有事务要求的多个操作, 可以直接使用非事务型管道进行处理, 减少事务产生的性能消耗

# 创建redis连接
redis_client = StrictRedis(host='127.0.0.1', port=6379, db=0, decode_responses=True)

# 创建非事务型管道  通过transaction=False参数设置
pipe = redis_client.pipeline(transaction=False)

# 使用管道对象进行数据操作   这些操作不会添加到事务中
a = pipe.set('name', 'zs')
b = pipe.set('age', 30)

# 只是将管道中的操作一起发送给redis服务器, 不会进行watch遍历和检查
c = pipe.execute()

print(a)
print(b)
print(c)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值