事务
Redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行。
因此,有特性:一次性、顺序性、排他性。
Redis事务没有隔离级别的概率,所有的命令在事务中,并没有被直接执行。只有发起执行命令exec的时候才会执行。
原子性:要么同时成功,要么同时失败
Redis单条命令是保证原子性的,但事务不保证原子性。
Redis的事务:
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)
正常执行事务
1
2
3
4
5
6
7
8
9
10
11
12
13
| 127.0.0.1:6379> multi # 开启事务
OK
# 命令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v2
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) OK
2) OK
3) OK
|
放弃事务 discard
1
2
3
4
5
6
7
8
9
10
11
12
| 127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> get k4
QUEUED
127.0.0.1:6379(TX)> discard # 取消事务,事务队列中的命令都不会被执行
OK
127.0.0.1:6379> get k4
(nil)
|
编译型异常(代码有问题!命令有错),事务中所有的命令都不会被执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> gettt k2 # 错误的命令
(error) ERR unknown command 'gettt', with args beginning with: 'k2'
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1 # 所有的命令都不会被执行
(nil)
|
运行时异常(1/0),如果事务队列中存在语法错误,那么执行命令的时候,其它命令可以正常执行,错误命令抛出异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| 127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 "v1"
QUEUED
127.0.0.1:6379(TX)> incr k1 # 执行失败
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range # 虽然报错,但事务依然正常执行
3) OK
4) OK
5) "v3"
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
|
乐观锁
认为什么时候都不会出问题,无论做什么都不会上锁。更新数据的时候判断一下在此期间内是否有人修改过数据。
悲观锁,认为什么时候都会出问题,无论做什么都会加锁。
监控 watch
正常执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 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 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec # 比对监视的值是否发生了变化,没变,事务正常执行,期间money没有发生变动
1) (integer) 80
2) (integer) 20
|
测试多线程修改值,监视失败,使用watch可以当作redis乐观锁使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 127.0.0.1:6379> watch money # 监视money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec # 执行之前,另外一个线程修改了money的值,这个时候会导致事务执行失败
(nil)
127.0.0.1:6379> unwatch # 如果发现事务执行失败,就先放弃监视
OK
127.0.0.1:6379> watch money # 重新监视,获取最新的值
OK
|
Jedis
Jedis是Redis官方推荐的java连接开发工具!使用Java操作Redis操作Redis中间件!如果要使用Java操作redis,那么一定要对redis十分熟悉。
测试
- 导入对应的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <dependencies>
<!-- 导入jedis包-->
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.3</version>
</dependency>
<!-- fastjson-->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.8</version>
</dependency>
</dependencies>
|
- 编码测试