目录

深入

事务

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. 导入对应的依赖
 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>
  1. 编码测试
    • 连接数据库
    • 断开命令
    • 断开连接