基本概念
- Redis的事务本质是一组命令的集合,一个事务中所有的命令都会被序列化,按照顺序执行
- Redis的单条语句保持原子性,但是事务不保持原子性
- Redis的事务没有隔离级别的概念
- Redis事务中的所有命令,只有在发起执行命令Exec后才会执行
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> get k2
QUEUED
127.0.0.1:6379> exec #执行事务
1) OK
2) OK
3) "v1"
4) OK
5) "v2"
127.0.0.1:6379>
放弃事务(discard)
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> discard #放弃事务
OK
127.0.0.1:6379> get k1 #队列中的命令都不会执行
(nil)
事务执行中的错误
- 编译型错误,即代码本身写的有问题,那么队列中所有命令的执行都不会成功
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> setget 666
(error) ERR unknown command `setget`, with args beginning with: `666`,
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)
- 运行时异常,例如写了1/0这样的代码,其本身语法没有错误,那么其他语句可以正常执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> incr k1 #语句本身没问题,但是key并不能自增
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
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) "v1"
5) "v2"
锁
锁的分类
- 悲观锁:悲观的认为什么时候都会出问题,无论做什么都会加锁
- 乐观锁:乐观的认为什么时候都不会出问题,只会在更新数据的时候去判断该数据是否被改动过,例如MySQL中的version字段
Redis中的乐观锁,监控 watch
- 单线程操作,不监视的情况下,对数据进行改动
127.0.0.1:6379> set money 1000
QUEUED
127.0.0.1:6379> set out 0
QUEUED
127.0.0.1:6379> decrby money 200 #余额减少200
QUEUED
127.0.0.1:6379> incrby out 200 #话费增加200
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (integer) 800
4) (integer) 200
-
多线程的情况下,如果进行了监视,而期间另一个线程对数据进行了改动
线程一,在exec前执行线程2
127.0.0.1:6379> watch money #监控money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 200
QUEUED
127.0.0.1:6379> incrby out 200
QUEUED
127.0.0.1:6379> exec #提交事务失败
(error) EXECABORT Transaction discarded because of previous errors.
线程二
127.0.0.1:6379> set money 2000
OK
查看现在的money为2000,代表事务提交失败
127.0.0.1:6379> get money
"2000"