• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Redis事务(Jedis实现)、实现乐观锁

redis 海叔叔 4年前 (2021-09-04) 27次浏览 已收录 0个评论
文章目录[隐藏]

Redis事务

Redis事务简介

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

一次性;顺序性;排他性

Redis事务执行顺序

1、开启事务(multi)
2、命令入队(多条命令)
3、执行事务(exec)

Redis事务相关命令

1、watch key1 key2 … : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )
2、multi : 标记一个事务块的开始( queued )
3、exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 )
4、discard : 取消事务,放弃事务块中的所有命令
5、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><a href="https://www.gaodaima.com/tag/redis" title="查看更多关于redis的文章" target="_blank">redis</a>.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"));
        }
    }
}

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Redis事务(Jedis实现)、实现乐观锁
喜欢 (1)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址