1.事务
1.1.Redis事务的概念
Redis事务本质上是一组命令的集合,事务执行一组命令时,所有这组命令将会被序列化,再执行过程中会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
- 关系型数据库的事务四大特性:ACID。原子性、一致性、隔离性、持久性。
Redis的单条命令保证原子性,但是事务不保证原子性,且不会回滚,
Redis也没有隔离级别的概念。所有的命令一次性、顺序性、排他性地执行一系列命令
1.2.事务三个阶段
- 开启事务(multi)
- 命令入队
- 执行事务(exec)或放弃事务(discard)
- 正常执行事务
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 k3 v3
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec # 执行事务
1) OK
2) OK
3) OK
4) "v2"
- 取消事务
127.0.0.1:6379> MULTI # 开启事务
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> get k5
QUEUED
127.0.0.1:6379> DISCARD # 取消事务
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
1.3.事务异常
- 编译型异常
若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行
127.0.0.1:6379> MULTI # 开启事务
OK
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> asdfasf # 随便输入命令
(error) ERR unknown command 'asdfasf' # 报错,但仍在队列中
127.0.0.1:6379> get k4
QUEUED
127.0.0.1:6379> exec # 执行事务,失败,报错,所有命令都不执行
(error) EXECABORT Transaction discarded because of previous errors.
- 运行时异常
若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> incr k1 # 字符串自增1
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec # 执行事务
1) "v1"
2) (error) ERR value is not an integer or out of range # k1是字符串,自增1时报错,但其他命令仍被执行
3) OK
1.1.Redis实现乐观锁
watch [keyname
加锁;unwatch [keyname]
解锁
#线程1
127.0.0.1:6379> set money 100 #添加金钱100
OK
127.0.0.1:6379> set cost 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 20
QUEUED
127.0.0.1:6379> INCRBY cost 20
QUEUED
###############先不执行,先执行线程2
127.0.0.1:6379> exec #执行报错,因为我们监视了money这个值,另一条线程改变了money的值,事务执行失败!
(nil)
127.0.0.1:6379> UNWATCH # 解锁
OK
#线程2
127.0.0.1:6379> INCRBY money 20 #金钱+20
(integer) 120