Redis基础
事务
Redis 事务的本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行!
一次性、顺序性、排他性的执行命令!
Redis的事务中没有隔离级别的概念,也就不可能发生脏读、幻读!
所有的命令在事务中,并没有直接被执行,而是在发起执行命令的时候,才会一起执行!
Redis的单条命令保持原子性,但是事务是不保证原子性的!
Redis的事务:三步!
- 开启事务:
multi
- 命令入队:普通的命令
- 执行事务:
exec
正常执行事务
127.0.0.1:6379> multi #开启事务
OK
#命令入队
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec #执行事务
1) OK
2) OK
3) "v1"
4) OK
放弃事务
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> discard #放弃事务
OK
127.0.0.1:6379> get k4 #队列都不会被执行
(nil)
编译型异常(Java中是代码错误,Redis中就是命令错误),事务中的一切命令都不会被执行
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> sets k2 v2 #错误的命令
(error) ERR unknown command `sets`, with args beginning with: `k2`, `v2`,
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec #执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k3 #所有的命令都不会执行
(nil)
运行时异常(就是语法错误,比如1/0),执行事务的时候,其他命令可以正常执行!错误命令抛出异常
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 k2
QUEUED
127.0.0.1:6379> incr k1 #语法错误,不能对字符串进行自增
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range #报出语法错误
3) OK
4) "v2"
127.0.0.1:6379> get k2 #其他命令正常执行!
"v2"
127.0.0.1:6379> get k1
"k2"
乐观锁
顾名思义:就很乐观,认为什么时候都不会出错,所以不会上锁!
没加锁,那么万一有人改动数据怎么办呢?更新的时候去判断一下,在此期间有没有人去修改这个数据就好了!
Redis监视测试!
watch
- 正常执行成功
127.0.0.1:6379> set money 100 #你银行卡里有100块钱
OK
127.0.0.1:6379> set out 0 #支出为0
OK
127.0.0.1:6379> watch money #监视你的银行卡
OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> decrby money 30 #花了三十买了点吃的
QUEUED
127.0.0.1:6379> incrby out 30 #这时候支出30,记着帐回家报销
QUEUED
127.0.0.1:6379> exec #执行事务
1) (integer) 70
2) (integer) 30
- 多线程修改值,执行失败
#第一个线程,就是你自己
127.0.0.1:6379> watch money #监视银行卡
OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> decrby money 20 #准备再花20块钱给你媳妇买朵花
QUEUED
127.0.0.1:6379> incrby out 20 #马上又得支出20
QUEUED
#这时候你还没有执行事务,你媳妇(第二个线程)发善心了,给你零花钱打进去了100块钱,你还不知道这事,但是被监视到了银行卡余额变化了!
127.0.0.1:6379> get money #一看你已经剩70块钱了
"70"
127.0.0.1:6379> incrby money 100 #马上给你又发了100块零花钱
(integer) 170
#这时候你再执行事务,就会失败 (第一个线程)
127.0.0.1:6379> exec #执行失败
(nil)
那么怎么解决这个问题呢,你还急着想买东西呢!发现钱用不了就很僵硬
#很简单,你先 去掉监视,然后重新监视最新数据就好啦,相当于刷新一下得到最新数据,再次监视
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> decrby money 20 #花二十
QUEUED
127.0.0.1:6379> incrby out 20 #支出加二十
QUEUED
127.0.0.1:6379> exec #执行事务,比对监视的值有没有发生变化,如果变化了就失败,反之则成功!
1) (integer) 150
2) (integer) 50
乐观锁可以用于秒杀场景!