《分布式中间件技术实战:Java版》学习笔记(一):抢红包

这篇具有很好参考价值的文章主要介绍了《分布式中间件技术实战:Java版》学习笔记(一):抢红包。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

数据库建表

(1)red_send_record
记录用户发送了若干总金额的若干个红包。

CREATE TABLE `red_send_record`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `user_id` int(0) NOT NULL COMMENT '用户id',
  `red_packet` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '红包全局唯一标识串',
  `total` int(0) NOT NULL COMMENT '人数',
  `amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '总金额(单位分)',
  `enable_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '是否有效',
  `create_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) 

(2)red_detail
记录用户发送的红包被分成的小红包金额。

CREATE TABLE `red_detail`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `red_packet` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(8, 2) NULL DEFAULT NULL,
  `enable_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1',
  `create_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE
)

(3)red_rob_record
记录用户抢到的红包金额。

CREATE TABLE `red_rob_record`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `user_id` int(0) NOT NULL,
  `red_packet` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(8, 2) NOT NULL,
  `create_time` timestamp(0) NULL DEFAULT NULL,
  `enable_flag` char(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1',
  PRIMARY KEY (`id`) USING BTREE
)
随机生成红包金额

红包金额的最小单位是分,将红包金额放大100倍到int类型(为了方便生成随机数),保证红包金额至少是1。

第一种分红包的方式是:红包金额先按照红包数均分,再拿2份数量的金额生成随机数,这种方式生成的金额方差小。
第二种分红包的方式是:直接拿红包总金额生成随机数,这种方式生成的金额方差大。

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class RedPacketUtil {

    public static Random random = new Random();

    public static int min = 1;

    /**
     * 随机生成红包金额
     * @param totalAmount 总金额
     * @param totalNum 红包个数
     * @return
     */
    public static List<Double> devideRedPacket(int totalAmount, int totalNum) {
        List<Double> result = new ArrayList();

        while(totalNum > 1) {
            int max = totalAmount / totalNum * 2;
            int randomAmount = min + random.nextInt(max);
            double amountResult = (double)randomAmount / 100;
            result.add(amountResult);

            totalAmount -= randomAmount;
            totalNum--;
        }

        result.add((double)totalAmount / 100);

        return result;
    }

    public static List<Double> devideRedPacket2(int totalAmount, int totalNum) {
        List<Double> result = new ArrayList();

        int splitAmount = totalAmount - totalNum * min;

        while(totalNum > 1) {

            int randomAmount = random.nextInt(splitAmount);
            double amountResult = (double)(randomAmount + min) / 100;
            result.add(amountResult);

            splitAmount -= randomAmount;
            totalNum--;
        }

        result.add((double)(splitAmount + min) / 100);

        return result;
    }   
}

单元测试:

@Test
public void testRedPacket() {
    List<Double> result = RedPacketUtil.devideRedPacket(2000, 10);
    AtomicReference<Double> total = new AtomicReference<>((double) 0);
    result.stream().forEach(data -> {
        System.out.println(data);
        total.updateAndGet(v -> new Double((double) (v + data)));
    });
    System.out.println("total = " + total);
}
发红包

发红包的请求参数是用户唯一标识、红包总金额和红包个数。

import lombok.Data;
import java.io.Serializable;

@Data
public class RedSendRecordDTO implements Serializable {
    private int userId;
    private int total;
    private double amount;
}

将分好的随机红包金额放入redis的List集合中,设置24小时失效。异步将用户发红包记录和随机红包金额写入数据库。

数据库操作直接引入Mybatis-plus

public String sendRedPacket(RedSendRecordDTO redSendRecordDTO) {
    String redPacket = UUID.randomUUID().toString();

    List<Double> amountPerRedPacket = RedPacketUtil.devideRedPacket((int)redSendRecordDTO.getAmount() * 100, redSendRecordDTO.getTotal());

    amountPerRedPacket.stream().forEach(amount -> {
        redisTemplate.opsForList().rightPush(redPacket, amount);
    });
    redisTemplate.expire(redPacket, 24, TimeUnit.HOURS);

    CompletableFuture.runAsync(new Runnable() {
        @Override
        public void run() {
            RedSendRecord redSendRecord = new RedSendRecord();
            redSendRecord.setRedPacket(redPacket);
            redSendRecord.setAmount(redSendRecordDTO.getAmount());
            redSendRecord.setUserId(redSendRecordDTO.getUserId());
            redSendRecord.setTotal(redSendRecordDTO.getTotal());
            save(redSendRecord);

            amountPerRedPacket.stream().forEach(amount -> {
                RedDetail redDetail = new RedDetail();
                redDetail.setRedPacket(redPacket);
                redDetail.setAmount(amount);
                redDetailService.save(redDetail);
            });
        }
    });

    return redPacket;
}

《分布式中间件技术实战:Java版》学习笔记(一):抢红包
《分布式中间件技术实战:Java版》学习笔记(一):抢红包

抢红包

抢红包入参是用户唯一标识、红包唯一标识。

import lombok.Data;
import java.io.Serializable;

@Data
public class RedRobRecordDTO implements Serializable {
    private int userId;
    private String redPacket;

}

抢红包要防止用户重复抢红包和一个红包被多个用户抢到。

(1)为了方便jmeter测试,在没有传userId参数时,生成一个随机用户标识。

(2)用redis的map存放用户标识和抢到的红包金额。

(3)先判断该用户之前有没有抢过红包,抢过直接返回抢到的红包金额。如果没有抢过,向redis添加一个key-value,如果添加成功,标识该用户可以抢红包,如果添加失败,标识该用户重复抢红包了。

(4)从redis存放随机红包金额的集合弹出一个红包给可以抢红包的用户,并保存到数据库。如果随机红包金额集合弹出的元素为空,表示红包抢完了。

@Override
public String robRedPacket(RedRobRecordDTO redRobRecordDTO) {
    if(0 == redRobRecordDTO.getUserId()) {
        int userId = RedPacketUtil.random.nextInt(1000);
        redRobRecordDTO.setUserId(userId);
    }
    log.info("robRedPacket redRobRecordDTO is:{}", JSONUtil.toJsonStr(redRobRecordDTO));

    //标识用户正在抢红包
    String userRobKey = redRobRecordDTO.getRedPacket() + ":" + redRobRecordDTO.getUserId();
    //用户抢到的红包金额
    String userAmountKey = redRobRecordDTO.getRedPacket() + ":amount";

    //判断用户是否抢过
    boolean isRobed = redisTemplate.opsForHash().hasKey(userAmountKey, redRobRecordDTO.getUserId());
    if(isRobed) {
        double amountPerUserId = (double) redisTemplate.opsForHash().get(userAmountKey, redRobRecordDTO.getUserId());
        return String.valueOf(amountPerUserId);
    }

    boolean isSet = redisTemplate.opsForValue().setIfAbsent(userRobKey, redRobRecordDTO.getUserId(), 1, TimeUnit.MINUTES);
    if(!isSet) {
        return "抢过了";
    }

    //抢到红包
    Double value = (Double) redisTemplate.opsForList().rightPop(redRobRecordDTO.getRedPacket());
    if(value == null) {
        return "红包被抢完了";
    }
    redisTemplate.opsForHash().put(userAmountKey, redRobRecordDTO.getUserId(), value);
    RedRobRecord redRobRecord = new RedRobRecord();
    redRobRecord.setUserId(redRobRecordDTO.getUserId());
    redRobRecord.setAmount(value);
    redRobRecord.setRedPocket(redRobRecordDTO.getRedPacket());
    redRobRecordService.save(redRobRecord);
   return String.valueOf(value);
}

《分布式中间件技术实战:Java版》学习笔记(一):抢红包
《分布式中间件技术实战:Java版》学习笔记(一):抢红包文章来源地址https://www.toymoban.com/news/detail-499231.html

到了这里,关于《分布式中间件技术实战:Java版》学习笔记(一):抢红包的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微服务中间件-分布式缓存Redis

    – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: 1.数据丢失问题: Redis是内存存储,服务重启可能会丢失数据 2.并发能力问题: 单节点Redis并发能力虽然不错,但也无法满足如618这样的高并发场景 3.故障恢复问题: 如果Redis宕机,则服务不可用,需要一种自动

    2024年02月12日
    浏览(54)
  • 分布式消息中间件RocketMQ的应用

    所有代码同步至GitCode:https://gitcode.net/ruozhuliufeng/test-rocketmq.git 普通消息 消息发送分类 ​ Producer对于消息的发送方式也有多种选择,不同的方式会产生不同的系统效果。 同步发送消息 ​ 同步发送消息是指,Producer发出一条消息后,会在收到MQ返回的ACK之后才发下一条消息。

    2024年02月05日
    浏览(71)
  • 微服务中间件--分布式搜索ES

    elasticsearch是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。 elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域。 elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。 正向索引

    2024年02月11日
    浏览(28)
  • golang分布式中间件之kafka

    Kafka是一个分布式发布-订阅消息系统,由LinkedIn公司开发。它被设计为快速、可靠且具有高吞吐量的数据流平台,旨在处理大量的实时数据。Kafka的架构是基于发布-订阅模型构建的,可以支持多个生产者和消费者。 在本文中,我们将讨论如何使用Go语言来实现Kafka分布式中间件

    2024年02月07日
    浏览(39)
  • Springcloud中间件-----分布式搜索引擎 Elasticsearch

    该笔记是根据黑马程序员的课来自己写了一遍的,b站有对应教程和资料 第一部分 第二部分 第三部分 预计看完跟着练习5小时足够 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 例如:

    2024年02月08日
    浏览(43)
  • ShardingSphere:强大的分布式数据库中间件【图文】

    Sharding-JDBC :它提供了一个轻量级的 Java 框架,在 Java 的 JDBC 层提供额外的服务。使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。Sharding-JDBC主要用于嵌入到应用程序中,使应用程序能够透明地

    2024年04月28日
    浏览(39)
  • 在CSDN学Golang分布式中间件(ElasticSearch)

    倒排索引是一种用于快速查找文本中特定单词或短语的数据结构。它将文本中的每个单词或短语与包含该单词或短语的文档列表相关联。这使得可以轻松地查找包含给定单词或短语的所有文档。 在 Go 中,可以使用 map 和 slice 来实现倒排索引。具体来说,可以使用一个 map 将每

    2024年02月15日
    浏览(34)
  • 第5章 分布式缓存中间件的配置及其调用定义

    1 分布式缓存中间件的配置定义 1.1 Core.Configuration. CacheConfig namespace Core . Configuration {     /// summary     /// 【缓存配置 -- 类】     /// remarks     /// 摘要:     ///     通过该类中的属性成员实例对 “appsettings.json” 文件中的 1 个指定缓存项 ( 键 / 值对 ) 在内存或指定分布式软

    2024年02月03日
    浏览(46)
  • XXL-JOB中间件【实现分布式任务调度】

    目录 1:XXL-JOB介绍 2:搭建XXL-JOB 2.1:调度中心 2.2:执行器 2.3:执行任务 3:分片广播 XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 官网:https://www.xuxueli.com/xxl-

    2024年02月03日
    浏览(94)
  • 削峰填谷与应用间解耦:分布式消息中间件在分布式环境下并发流量控制的应用

    这是《百图解码支付系统设计与实现》专栏系列文章中的第(18)篇,也是流量控制系列的第(4)篇。点击上方关注,深入了解支付系统的方方面面。 本篇重点讲清楚分布式消息中间件的特点,常见消息中间件的简单对比,在支付系统的应用场景,比如削峰填谷,系统应用间

    2024年01月20日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包