您现在的位置是:首页 >其他 >Redis:事务操作以及监控(悲观锁,乐观锁)网站首页其他

Redis:事务操作以及监控(悲观锁,乐观锁)

不想睡醒的梦 2024-06-14 17:17:21
简介Redis:事务操作以及监控(悲观锁,乐观锁)

什么是事务?

事务操作是指:在一组操作中,有很多的命令,如果在这组操作时,有一个命令出现的了bug,那么这组这组操作会进行回滚,将环境还原成没有开始这组操作时的状态。在MySQL等关系型数据库中事务操作可能会出现这种结果,但是在redis则也可能出现其他的错误,那就是语法问题,通俗的讲就是在MySQL数据库中实现转账业务,一个人的金额增加,一个人减少,如果失败那么两人就不会有任何变化,但是在redis则不同,它也有可能出现,一个人的金额增加,但是另外的哪一个人金额并没有减少,下面会讲到。

事务操作支持多项命令,命令会被序列化,通俗的来讲就是命令会被放入一个队列中。

在事务操作过程中,执行步骤会按照队列中的顺序进行执行,队列之外的命令并不会插入执行事务操作执行命令的过程中。

单一的命令执行保持原子性,但是事务操作却不会保持原子性,就是要么成功的执行全部,要么则是白用功,回到故事的开端,重新开始。

在redis中执行事务

注意:开启事务后,会出现 TX 标志,此时所有的操作不会马上有结果,而是形成队列(QUEUED),待执行事务后,会将所有命令按顺序执行。

开启事务

127.0.0.1:6379> FLUSHALL      清空redis数据库             
OK
127.0.0.1:6379> MULTI               开启事务操作
OK
127.0.0.1:6379(TX)> set key1 v1       命令,但不是直接执行,这项命令会被放到队列中
QUEUED
127.0.0.1:6379(TX)> set key1 v2
QUEUED
127.0.0.1:6379(TX)> set key2 v1
QUEUED
127.0.0.1:6379(TX)> get key2
QUEUED
127.0.0.1:6379(TX)> set key3 v3
QUEUED
127.0.0.1:6379(TX)> exec         执行队列中命令,就是前面的几行命令
1) OK                                         这是执行命令中的结果                                          

2) OK
3) OK
4) "v1"
5) OK
127.0.0.1:6379> keys *     命令执行成功
1) "key3"
2) "key2"
3) "key1"
127.0.0.1:6379> 

 放弃事务:DISCARD

127.0.0.1:6379> FLUSHALL
OK 
127.0.0.1:6379> MULTI                  开启事务                                     
OK
127.0.0.1:6379(TX)> set key1 v1    
QUEUED
127.0.0.1:6379(TX)> set key2 v2
QUEUED
127.0.0.1:6379(TX)> set key3 v3
QUEUED
127.0.0.1:6379(TX)> DISCARD     取消事务
OK
127.0.0.1:6379> keys *           事务并没有执行,取消成功
(empty array)
127.0.0.1:6379> 

事务中的命令存在错误:编译性错误

127.0.0.1:6379> MULTI         
OK
127.0.0.1:6379(TX)> set key1 v1                      创建一个key,加入到队列当中
QUEUED
127.0.0.1:6379(TX)> getset key1                      错误的命令
(error) ERR wrong number of arguments for 'getset' command     报错
127.0.0.1:6379(TX)> set key2 v2                      再创建一个key,加入到队列当中
QUEUED
127.0.0.1:6379(TX)> exec                                执行事务操作
(error) EXECABORT Transaction discarded because of previous errors.   报错
127.0.0.1:6379> keys *                                     事务中的所有命令,都没有被执行
(empty array)
127.0.0.1:6379> 

运行错误:加入队列中命令没有问题,但是执行命令可能存在一些语法性的问题,这时队列中的问题依旧会被执行,这个问题就是我在上面提到的转账业务,一个人会增加,但是另外一个人却不一定会减少。

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> set key1 v1     创建一个key
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR key1   让先前创建的key+1,但是因为创键的key1是字符串,所以此代码执行可能会报错,但是这行代码在语法是没有错误,它能正常的添加到队列中。
QUEUED                                        添加成功
127.0.0.1:6379(TX)> set key2 v2   创建几个其他的可以
QUEUED
127.0.0.1:6379(TX)> get key2
QUEUED
127.0.0.1:6379(TX)> EXEC          执行队列中的方法
1) (error) ERR value is not an integer or out of range  队列的第一条命令报错
2) OK                                                                            其他的命令正常执行
3) "v2"
127.0.0.1:6379>  

监控:watch

乐观锁:

        乐观主义者,认为数据并不会出现问题,并不会进行上锁,在更新数据时,要与监控时数据进行比较,如果有人更改数据,则数据并不会发生改变。

        获取version

        在执行操作命令时去比较version时候发生改变

悲观锁:

        悲观主义者:认为数据无论在什么时候都有可能出现问题,什么数据都上锁 

redis测试监控

正常情况下

127.0.0.1:6379> FLUSHALL 
OK
127.0.0.1:6379> set money 100    设置初始值
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money   对money进行监控
OK
127.0.0.1:6379> MULTI                  开启事务
OK
127.0.0.1:6379(TX)> DECRBY money 10   减少10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10        增加10
QUEUED
127.0.0.1:6379(TX)> EXEC                   执行队列命令,并不会发生任何问题,正常执行
1) (integer) 90
2) (integer) 10
127.0.0.1:6379> 

 在多线程环境里出现乐观锁时

线程一:

127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCRBY out 50
QUEUED
127.0.0.1:6379(TX)> DECRBY money 50
QUEUED
127.0.0.1:6379(TX)> get money
QUEUED

当线程一正在执行事务时这是线程二介入修改了money的数据值 

线程二:

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> 

那么线程一执行事务,会出现怎样的结果呢?

127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCRBY out 50
QUEUED
127.0.0.1:6379(TX)> DECRBY money 50
QUEUED
127.0.0.1:6379(TX)> get money
QUEUED
127.0.0.1:6379(TX)> EXEC             队列中命令全都执行失败
(nil)
127.0.0.1:6379>  

出现乐观锁问题,之后又如何执行完线程一的操作呢?

127.0.0.1:6379> unwatch           首先先解锁
OK
127.0.0.1:6379> WATCH money 然后再上锁
OK
127.0.0.1:6379> MULTI                开启事务操作
OK
127.0.0.1:6379(TX)> DECRBY money 50
QUEUED
127.0.0.1:6379(TX)> INCRBY out 50
QUEUED
127.0.0.1:6379(TX)> get money
QUEUED
127.0.0.1:6379(TX)> EXEC                  执行,成功
1) (integer) 50
2) (integer) 60
3) "50"  
127.0.0.1:6379>  

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。