redis 事务/乐观锁

  • 使用命令 multi 表示开启一个事务,exex 表示提交事务,discard 表示放弃事务
  • 分为三个阶段:开启事务、执行命令(组队过程)、提交事务/放弃事务
    • 如果组队过程中有一个操作失败,整个事务失败
    • 如果提交事务时有操作失败,不影响整体事务(非原子性)
  • redis 支持乐观锁保证事务并发,开启事务前使用 watch 监视某个或多个 key 实现

事务正常

# 开启事务
127.0.0.1:6379> multi
OK
# 执行命令
127.0.0.1:6379(TX)> mset k1 v1 k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
# 提交事务
127.0.0.1:6379(TX)> exec
1) OK
2) OK

提交阶段失败

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k4 v4
QUEUED
# k1 不是整型,自增会失败,但是组队过程不会失败
127.0.0.1:6379(TX)> incr k1
QUEUED
# 执行结果中,第一条操作成功,第二条失败,整个事务就部分完成,不是原子性的
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range

组队阶段失败

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set b1 v1
QUEUED
# 这个操作没有设置值,肯定会失败,表示整个事务已经失败了
127.0.0.1:6379(TX)> set b2
(error) ERR wrong number of arguments for 'set' command
# 这时 exec 也没意义了,整个事务已经失败
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
# discard 也失去意义了
127.0.0.1:6379> discard
(error) ERR DISCARD without MULTI

乐观锁示例

两个事务都监听 k5,加 20 的事务先提交,加 10 的事务就会失败,返回 nil

# 事务 1,给 k5 + 10(这个事务后提交)
127.0.0.1:6379> watch k5
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby k5 10
QUEUED
127.0.0.1:6379(TX)> exec
(nil)

# 事务 2,给 k5 + 20(这个事务先提交)
127.0.0.1:6379> watch k5
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby k5 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 120

数据库乐观锁 sql:update t_user set username = 'zhangsan', version = version+1 where id = 1 and version = 原来的值,原理是判断 version 的值。现在 redis 的 watch 和事务可以代替数据库的 version 机制,每次数据库 update 之前先 redis 更新

  • 如果成功,就说明没有别的事务更新这个值,此时允许数据库 update
  • 如果失败,就不允许数据库 update
posted @ 2023-07-10 15:52  CyrusHuang  阅读(10)  评论(0编辑  收藏  举报