Redis事务

Redis事务简介

Redis事务的本质是一组命令的执行,一个事务中的所有命令都会被序列化,所有命令按照入队的顺序执行,先入队的先执行;Redis事务没有隔离级别;单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

一次性;顺序性;排他性

Redis事务执行顺序

  • 开启事务(multi)
  • 命令入队(多条命令)
  • 执行事务(exec)

Redis事务相关命令

  •   watch key1 key2 ... : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )
  •   multi : 标记一个事务块的开始( queued )
  •   exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 ) 
  •   discard : 取消事务,放弃事务块中的所有命令
  •   unwatch : 取消watch对所有key的监控

事务正常执行时

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> exec #执行事务
1) OK
2) OK
3) "v1"

执行事务过程中取消事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379> LPUSH list 1
QUEUED
127.0.0.1:6379> LPUSH list 2
QUEUED
127.0.0.1:6379> LPUSH list 3
QUEUED
127.0.0.1:6379> LRANGE list 0 -1
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI #事务取消后,multi指令也随之消失,命令无效
127.0.0.1:6379> LPOP list
(nil)

当执行事务时出错时

1)当exec执行事务前出错

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name kexing
QUEUED
127.0.0.1:6379> SMEMBERS
(error) ERR wrong number of arguments for 'smembers' command
127.0.0.1:6379> exec  #exec前处出错时,无法提交事务,即事务被丢弃
(error) EXECABORT Transaction discarded because of previous errors.

2)当exec执行事务后出错

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name kexing
QUEUED
127.0.0.1:6379> SADD name 1
QUEUED
127.0.0.1:6379> exec #exec后出错,出错的命令失败,其他命令成功
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get name
"kexing"

watch监控,实现乐观锁

1)正常情况下:

127.0.0.1:6379> multi   #开启事务
OK
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 10 #余额-10
QUEUED
127.0.0.1:6379> incrby out 10  #花出+10
QUEUED
127.0.0.1:6379> exec #执行 
1) OK
2) OK
3) (integer) 990
4) (integer) 10

2)使用watch监控money,当事务执行过程中money发生改变,提交事务会失败,提交后自动unwatch解锁

127.0.0.1:6379> get money
"990"
127.0.0.1:6379> get out
"10"
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby money 10
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get money
"1000"

在上面事务执行过程中(未提交),更改了money的值

127.0.0.1:6379> incrby money 10
(integer) 1000

watch检测到money值发生改变,因此不允许此次事务的执行,执行事务失败,当事务执行后,无论成功失败,都会自动unwatch解锁

Jedis操作事务

导入jedis、fastjson依赖

<dependencies>
        <!-- jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>
    </dependencies>
public class RedisAffairs {
    public static void main(String[] args) {

        Jedis jedis = new Jedis("127.0.0.1",6379);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name","kexing");
        jsonObject.put("age","20");
        jsonObject.put("sex","0");
        String user = jsonObject.toJSONString();
        jedis.flushDB();
        //开启事务
        Transaction multi = jedis.multi();
        //命令入队
        try {
            multi.set("user1",user);
            multi.sadd("user1","1","2");  //运行时错误
            multi.set("user2",user);
            multi.exec();
        }catch (Exception e){
            //命令错误,事务取消
            multi.discard();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
        }
    }
}
最后修改:2021 年 01 月 16 日 03 : 49 PM
如果觉得我的文章对你有用,请随意赞赏