Redis事务+AOF模式,实现司机抢单

        我们知道了Redis的事务,可以在秒杀中避免出现超售现象,如果用在司机抢单上面,也能避免一个订单被多个司机抢单成功。这节课咱们就把Redis事务和Java程序结合在一起,我们完成司机抢单的后端代码。

        由于Redis使用内存缓存数据,如果Redis宕机,重启Redis之后,原本内存中缓存的数据就全都消失了。为了在宕机之后能有效恢复之前缓存的数据,我们可以开启Redis的持久化功能。

        Redis有RDB和AOF两种持久化方式。RDB会根据指定的规则定时将内存中的数据保存到硬盘中,容易因为持久化不及时,导致恢复的时候丢失一部分缓存数据。AOF会将每次执行的命令及时保存到硬盘中,实时性更好,丢失的数据更少,所以本课程中我们选择AOF模式。

        修改Redis配置文件,把原本的save注释掉,然后添加上新的save设置。在结尾还要追加两句话,然后重新启动Redis容器。

bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
logfile ""
databases 12
save ""
#save 900 1
#save 300 10
#save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir ./
requirepass abc123456
appendonly yes
appendfilename "appendonly.aof"
appendfsync always

        在com.example.hxds.odr.service.implOrderServiceImpl.java类中,实现抽象方法。

@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private RedisTemplate redisTemplate;
    ……

    @Override
    @Transactional
    @LcnTransaction
    public String acceptNewOrder(long driverId, long orderId) {
        //Redis不存在抢单的新订单就代表抢单失败
        if (!redisTemplate.hasKey("order#" + orderId)) {
            return "抢单失败";
        }
        //执行Redis事务
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                //获取新订单记录的Version
                operations.watch("order#" + orderId);
                //本地缓存Redis操作
                operations.multi();
                //把新订单缓存的Value设置成抢单司机的ID
                operations.opsForValue().set("order#" + orderId, driverId);
                //执行Redis事务,如果事务提交失败会自动抛出异常
                return operations.exec();

            }
        });
        //抢单成功之后,删除Redis中的新订单,避免让其他司机参与抢单
        redisTemplate.delete("order#" + orderId);
        //更新订单记录,添加上接单司机ID和接单时间
        HashMap param = new HashMap() {{
            put("driverId", driverId);
            put("orderId", orderId);
        }};
        int rows = orderDao.acceptNewOrder(param);
        if (rows != 1) {
            throw new HxdsException("接单失败,无法更新订单记录");
        }
        return "接单成功";

    }

    @Override
    public Integer searchOrderStatus(Map param) {
        Integer status = orderDao.searchOrderStatus(param);
        if (status == null) {
            throw new HxdsException("没有查询到数据,请核对查询条件");
        }
        return status;
    }

    @Override
    @Transactional
    @LcnTransaction
    public String deleteUnAcceptOrder(Map param) {
        long orderId = MapUtil.getLong(param, "orderId");
        if (!redisTemplate.hasKey("order#" + orderId)) {
            return "订单取消失败";
        }
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                operations.watch("order#" + orderId);
                operations.multi();
                operations.opsForValue().set("order#" + orderId, "none");
                return operations.exec();
            }
        });

        redisTemplate.delete("order#" + orderId);
        int rows = orderDao.deleteUnAcceptOrder(param);
        if (rows != 1) {
            return "订单取消失败";
        }
        return "订单取消成功";
    }
}

        个人总结:先执行Redis事务,避免超售现象。再执行Redis缓存删除 和 SQL操作。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

chengbo_eva

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

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

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

打赏作者

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

抵扣说明:

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

余额充值