Redis系列——第三章 Redis开启事务并实现乐观锁

11 篇文章 0 订阅
4 篇文章 0 订阅

Redis系列

Redis系列——第一章 Redis配置文件
Redis系列——第二章 Redis数据类型以及基本使用
Redis系列——第三章 Redis开启事务并实现乐观锁
Redis系列——第四章 Redis发布订阅模式
Redis系列——第五章 Redis持久化策略RDB与AOF
Redis系列——第六章 Redis主从同步
Redis系列——第七章 Redis开启哨兵模式

一、Redis事务

本质:一组命令的集合 要么一起成功 要么一起失败,一个事务中的所有命令都会被序列化,在事务执行过程中会按照顺序执行

注意:

  1. Redis单条命令是保证原子性的,但是事务是不保证原子性的
  2. Redis没有隔离级别的概念

首先我们需要了解 Redis底层是由C编写,命令直接交由CPU执行,而CPU一旦执行命令是不会被中断的,所以基本每一条指令都是原子性的。但是虽然Redis每一条指令都是原子性的但是一旦指令联合使用就有可能被打断,即没有原子性。

1、开启事务

multi命令

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 2
QUEUED
127.0.0.1:6379> set k2 3
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 1
QUEUED
127.0.0.1:6379>   

开启事务,所有在事务之后执行的命令都会进入队列 等待执行

2、执行事务

exec 命令——>执行事务队列的命令

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 2
QUEUED
127.0.0.1:6379> set k2 3
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 1
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "2"
4) OK
127.0.0.1:6379>   
3.取消事务

discard 命令

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 2
QUEUED
127.0.0.1:6379> set k2 3
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI  //没有事务可执行
127.0.0.1:6379>  
4、watch 监视命令

在这里插入图片描述
watch 监视命令:监视一个key值如果发生变化会导致事务执行失败,但是是一次性的操作所以每次执行失败后需要重新使用监视命令

与之对应的 UNwatch 放弃监视

二、使用redis事务实现乐观锁

  • 乐观锁:我很乐观,我不认为需要控制,数据不可能出问题,所以不上锁 典型:cas
  • 悲观锁:我很悲观,我认为数据无时无刻都有可能出现问题,所以我上锁了 典型:synchronized
代码
    public static void main(String[] args) throws InterruptedException {
       // 获取jedis连接
        Jedis jedis = new Jedis("127.0.0.1",6379);
        // 抢到的用户
        String key_s = "user_name";
        // 商品数量
        String key = "test_count";
        jedis.set("count","0");
        jedis.set(key,"100");
        for (int i= 0; i< 101;i++){
            new Thread(()-> testWatch(key_s ,key)).start();
        }
        Thread.sleep(5000);
        System.out.println("抢到用户数量为:" +jedis.get("count"));

    }

    public static void testWatch(String key_s ,String key){
        Jedis jedis = new Jedis("127.0.0.1",6379);
        try {
            //模拟用户
            String customer = UUID.randomUUID().toString().replace("-", "");

            while (true) {
                try {
                    //监控商品数量
                    jedis.watch(key);
                    System.out.println("用户:" + customer + "开始抢商品");
                    System.out.println("当前商品的个数:" + jedis.get(key));
                    int prdNum = Integer.parseInt(jedis.get(key));
                    if (prdNum > 0) {
                        //开启事务
                        Transaction transaction = jedis.multi();
                        transaction.set(key, String.valueOf(prdNum - 1));
                        //提交事务
                        List<Object> result = transaction.exec();
                        //如果监控失败 提示
                        if (result == null || result.isEmpty()) {
                            System.out.println("用户:" + customer + "没有抢到");
                            System.out.println("当前商品的剩余:" + jedis.get(key));
                        } else {
                            //记录抢到商品的用户信息 并记录用户个数
                            jedis.sadd(key_s, customer);
                            jedis.incr("count");
                            System.out.println("用户:" + customer + "抢到商品");
                            System.out.println("当前商品剩余个数:" + jedis.get(key));
                            break;
                        }
                    } else {
                        System.out.println("库存为0,用户:" + customer + "没有抢到商品");
                        break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    //exec,discard,unwatch命令都会清除连接中的所有监视
                    jedis.unwatch();
                }
            }
        } catch (Exception e) {
            // TODO: 处理Redis 错误或其他
            System.out.println("redis bug:" + e.getMessage());
        } finally {
            try {
               jedis.close();
            } catch (Exception e) {
                System.out.println("redis bug:" + e.getMessage());
            }
        }
    }

巧妙的使用redis事务的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值