Redis事务和过期处理

线程执行先后顺序和快慢是由操作系统和CPU自动决定的,为了解决这个问题可以使用Redis的事务

什么是事务

事务是指将一个业务逻辑作为一个整体一起执行,其实就是打包一组操作(或者命令)作为一个整体,在事务处理时将顺序执行这些操作,并返回结果,任何一个环节出错,所有的操作都会回滚.

Redis事务

提供一种将多个命令打包,一次性顺序的执行,Redis的事务可以保证只有在执行完事务中的所有命令后,才会继续处理此客户端的其他命令.也就是只有一个用户可以操作事务当中的数据.
在这里插入图片描述

开启事务命令

Redis事务四大指令:MULTI,EXEC,DISCARD,WATCH

  • MULTI开启一个事务
  • EXEC执行一个事务
  • DISCARD取消一个事务
  • WATCH用于客户端并发情况下,为事务提供一个锁,可以用watch命令来监控一个或多个变量如果在执行事务之前,某个监控项被修改,那么整个事务都会被终止

watch必须写在事务之前,不能写在后面

所以可以使用WATCH来处理抢购的并发情况
在这里插入图片描述

    public Result<Boolean> snappedUp(@RequestParam("id") Long id) {
        //初始化返回数据
        Result result = new Result();
        result.data(true);
        result.setSuccess(true);
        //实现购买代码
        //先去redis查询一下
        Object value = redisTemplate.opsForValue().get(id);
        int stock = 0;
        //如果redis没有则去数据库查询
        if (value == null) {
            //去数据库查询该商品的信息
            ProductDO product = productDAO.selectById(id);
            //将信息缓存到redis里边
            stock = product.getStock();
            redisTemplate.opsForValue().set(product.getId(), stock);
        } else {
            stock = (int)value;
        }

        redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations operations) throws DataAccessException {
                Integer stock = (Integer)operations.opsForValue().get(id);
                //判断该商品的库存是否大于1
                if (Integer.valueOf(stock) >= 1) {
                    //监听商品的名字,redis里边的key
                    operations.watch(id);

                    //开启事务
                    operations.multi();

                    //将该商品的库存自减1
                    operations.opsForValue().set(id, stock - 1);
                    //修改mysql数据库库存数量
                    ProductDO productDO = new ProductDO();
                    productDO.setId(id);
                    productDO.setStock(stock - 1);
                    productDAO.updateStock(productDO);
                    // 执行事务
                    List exec = operations.exec();
                    if (exec.size() > 0) {
                        // TODO:可以有其它业务逻辑,例如插入订单等,视具体需求而定
                        result.setMessage("抢购成功");
                        result.setData(true);
                    } else {
                        result.setMessage("抢购失败");
                        result.setData(false);
                    }

                    return exec;
                } else {
                    result.setMessage("商品库存不足");
                    result.setData(false);

                    return null;
                }
            }
        });

        return result;
    }

执行事务

redisTemplate.execute()是执行器的方法,可以执行一系列的操作,使用Redis事务时:

redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations operations) throws DataAccessException {
            }
        });

以上演示解决了并发的问题

Redis过期处理

很多时候服务器经常会用到Redis作为缓存,有很多时候是临时缓存,可能之后就不会在用到了,所以要定期处理

设置过期时间

对Redis数据库中的值可以设置一个过期时间,设置key有效时间Expires字典保存了所有键的过期时间

比如在1000毫秒后过期:

redisTemplate.opsForValue().set("code", "78987", 1000,TimeUnit.MILLISECONDS);
  • 1000为过期数
  • TimeUnit.MILLISECONDS)为时间单位

删除策略

  1. 惰性删除
    每次查询或者写键时,都会查键是否过期,过期就删除否则返回该键,对CPU友好,对内存不友好

  2. 定期删除
    每隔一段时间对数据库检查,删除里面的过期键.

  3. 定时删除
    在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-irony-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值