首页 > 其他 > 详细

Redis 副本-04 【Redis事务,悲观锁与乐观锁】

时间:2020-04-19 21:30:37      阅读:103      评论:0      收藏:0      [点我收藏+]

Redis 的事务

我们在学 MySQL 的时候就接触到了事务及 ACID 原则,其中很重要的一条原则:要么同时成功,要么同时失败!(原子性)。

Redis 单条命令是保存原子性的,但是 Redis 的事务是不保证原子性的

Redis 事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行。

技术分享图片

一次性顺序性排他性!执行一系列的命令。

Redis 事务没有隔离级别的概念!

所有的命令在事务中并没有被直接执行,只有发起执行命令的时候才会执行。

Redis 事务分为三个阶段:

  • 开启事务( MULTI )
  • 命令入队( ...... )
  • 执行事务( EXEC )

正常执行事务

127.0.0.1:6379> multi						# 开启事务
OK
127.0.0.1:6379> set key1 value1				# 命令入队
QUEUED
127.0.0.1:6379> get key1
QUEUED
127.0.0.1:6379> rpush number one two three
QUEUED
127.0.0.1:6379> lrange number 0 -1
QUEUED
127.0.0.1:6379> exec						# 执行事务
1) OK
2) "value1"
3) (integer) 3
4) 1) "one"
   2) "two"
   3) "three"

取消事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key2 value2
QUEUED
127.0.0.1:6379> rpush number four five
QUEUED
127.0.0.1:6379> discard						# 取消事务,队列中的命令都不会被执行
OK
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> lrange number 0 -1
1) "one"
2) "two"
3) "three"

如果事务中的命令有问题呢?

我们可以把 Redis 中的错误想象成 Java 中的两种异常:

  • 编译性异常(代码或命令有问题),事务中所有的命令都不会被执行
  • 运行时异常(例如:1/0),如果事务队列中的命令存在有语法错误,那么执行命令的时候其他正常的命令是可以执行的,错误命令抛出异常

编译性异常

127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key1 value1
QUEUED
127.0.0.1:6379> lpush list l1 l2
QUEUED
127.0.0.1:6379> setone key2 value2		# 错误命令
(error) ERR unknown command `setone`, with args beginning with: `key2`, `value2`, 
127.0.0.1:6379> set key3 value3
QUEUED
127.0.0.1:6379> exec					# 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get key1
(nil)
127.0.0.1:6379> get key3				# 所有的命令都没有执行
(nil)

运行时异常

127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name touyel
QUEUED
127.0.0.1:6379> incr name			# 语法错误
QUEUED
127.0.0.1:6379> set age 18
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> get name			# 正常命令执行成功
"touyel"
127.0.0.1:6379> get age
"18"

悲观锁和乐观锁

悲观锁

  • 很悲观,认为什么时候都会出现问题,无论做什么都会加锁

乐观锁

  • 很乐观,认为什么时候都不会出现问题,所以不会加锁,更新数据的时候去判断一下,在此期间是否有人修改过这个数据
  • 获取 version
  • 更新的时候比较 version

Redis 乐观锁

Redis 使用乐观锁只需了解一个命令:watch

Redis 监视测试( Watch )

正常执行成功:

127.0.0.1:6379> set t:money 200
OK
127.0.0.1:6379> set r:money 100
OK
127.0.0.1:6379> watch t:money			# 监视 t:money 对象
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby t:money 40
QUEUED
127.0.0.1:6379> incrby r:money 40
QUEUED
127.0.0.1:6379> exec					# 事务正常结束
1) (integer) 160
2) (integer) 140

测试多线程修改值,使用 watch 可以当作 Redis 的乐观锁操作

127.0.0.1:6379> keys *
1) "r:money"
2) "t:money"
127.0.0.1:6379> watch t:money			# 监视 t:money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby t:money 10
QUEUED
127.0.0.1:6379> incrby r:money 10
QUEUED

# 执行之前,另外一个线程修改了 t:money
127.0.0.1:6379> set t:money 300
OK

# 因为另外一个线程修改了 t:money ,导致事务执行失败
127.0.0.1:6379> exec
(nil)

如果修改失败,获取最新的值就好

127.0.0.1:6379> unwatch					# 如果发现事务执行失败,就先解锁
OK
127.0.0.1:6379> watch t:money			# 再次监视 t:money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby t:money 100
QUEUED
127.0.0.1:6379> decrby r:money 100
QUEUED
127.0.0.1:6379> exec					# 事务执行成功
1) (integer) 400
2) (integer) 40

Redis 副本-04 【Redis事务,悲观锁与乐观锁】

原文:https://www.cnblogs.com/touyel/p/12733451.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!