拼团退款中采用分片处理降低对数据库

完整拼团处理系统代码实现

一、核心实体类

/**
 * 拼团信息实体
 */
@Entity
@Table(name = "group_info")
@Data
public class Group {
    @Id
    @Column(name = "id", length = 32)
    private String id; // 使用雪花算法生成的ID

    @Column(name = "process_slot", nullable = false)
    private Integer processSlot; // 处理时间段(0-143)

    @Column(name = "expire_time", nullable = false)
    private Date expireTime; // 业务过期时间

    @Column(name = "status", length = 20)
    @Enumerated(EnumType.STRING)
    private GroupStatus status; // 状态枚举

    @Column(name = "created_time")
    private Date createdTime; // 创建时间
}

/**
 * 拼团状态枚举
 */
public enum GroupStatus {
    OPEN, // 进行中
    CLOSED, // 已关闭
    PROCESSING // 处理中
}

二、数据访问层

public interface GroupRepository extends JpaRepository<Group, String> {

    /**
     * 查询待处理拼团(分页查询保证性能)
     * @param currentSlot 当前时间槽
     * @param pageable 分页参数
     */
    @Query("SELECT g FROM Group g WHERE " +
           "g.processSlot = :slot AND " +
           "g.status = 'OPEN' AND " +
           "g.expireTime < CURRENT_TIMESTAMP")
    Page<Group> findGroupsToProcess(
        @Param("slot") Integer currentSlot, 
        Pageable pageable
    );

    /**
     * 批量更新状态(使用IN语句提升效率)
     */
    @Modifying
    @Query("UPDATE Group g SET g.status = :status " +
           "WHERE g.id IN :ids")
    int batchUpdateStatus(
        @Param("ids") List<String> ids,
        @Param("status") GroupStatus status
    );
}

三、服务层核心实现

@Service
@RequiredArgsConstructor
public class GroupService {

    private final GroupRepository groupRepository;
    private final RedisLockService redisLockService;
    private final MQService mqService;

    /**
     * 创建拼团(包含分片时间计算)
     */
    @Transactional
    public void createGroup(GroupCreateRequest request) {
        Group group = new Group();
        group.setId(SnowflakeGenerator.nextId()); // 雪花ID生成
        group.setExpireTime(calculateExpireTime(request.getDuration())); 
        group.setProcessSlot(calculateProcessSlot(group.getId()));
        group.setStatus(GroupStatus.OPEN);
        groupRepository.save(group);
    }

    /**
     * 计算处理时间槽(核心算法)
     */
    private Integer calculateProcessSlot(String groupId) {
        CRC32 crc32 = new CRC32();
        crc32.update(groupId.getBytes());
        return (int)(crc32.getValue() % 144); // 144=24h*6
    }

    /**
     * 定时任务处理方法
     */
    @Scheduled(cron = "0 */10 * * * ?") // 每10分钟执行
    @Async("taskExecutor") // 异步线程池
    public void processExpiredGroups() {
        // 1. 计算当前slot
        long currentSlot = (System.currentTimeMillis() / (10 * 60 * 1000)) % 144;

        // 2. 分页查询处理(防止内存溢出)
        int page = 0;
        Page<Group> groupPage;
        do {
            groupPage = groupRepository.findGroupsToProcess(
                (int)currentSlot, 
                PageRequest.of(page, 500) // 每页500条
            );

            // 3. 批量处理
            batchProcess(groupPage.getContent());

            page++;
        } while (groupPage.hasNext());
    }

    /**
     * 批量处理逻辑
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW) // 新事务
    public void batchProcess(List<Group> groups) {
        if (groups.isEmpty()) return;

        // 1. 获取分布式锁(按groupID加锁)
        String lockKey = "group_process:" + groups.get(0).getId();
        boolean locked = redisLockService.tryLock(lockKey, 30);
        if (!locked) return;

        try {
            // 2. 更新状态为处理中
            List<String> ids = groups.stream()
                .map(Group::getId)
                .collect(Collectors.toList());
            groupRepository.batchUpdateStatus(ids, GroupStatus.PROCESSING);

            // 3. 发送退款MQ消息
            groups.forEach(group -> {
                RefundMessage message = new RefundMessage();
                message.setGroupId(group.getId());
                message.setAmount(calculateRefundAmount(group));
                mqService.sendRefundMessage(message);
            });

        } finally {
            redisLockService.unlock(lockKey);
        }
    }
}

四、配置类

@Configuration
@EnableAsync
public class TaskConfig {

    /**
     * 定时任务线程池配置
     */
    @Bean("taskExecutor")
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("group-process-");
        executor.initialize();
        return executor;
    }

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        return template;
    }
}

五、分布式锁工具类

@Service
@RequiredArgsConstructor
public class RedisLockService {
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取分布式锁(简化版)
     */
    public boolean tryLock(String key, long expireSeconds) {
        return Boolean.TRUE.equals(
            redisTemplate.opsForValue()
                .setIfAbsent(key, "LOCKED", expireSeconds, TimeUnit.SECONDS)
        );
    }

    /**
     * 释放锁
     */
    public void unlock(String key) {
        redisTemplate.delete(key);
    }
}

六、消息队列处理

@Service @RequiredArgsConstructor public class MQService { private final RocketMQTemplate rocketMQTemplate;
/**
 * 发送退款消息
 */
public void sendRefundMessage(RefundMessage message) {
    rocketMQTemplate.asyncSend("REFUND_TOPIC", 
        MessageBuilder.withPayload(message).build(), 
        new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                log.info("退款消息发送成功: {}", message.getGroupId());
            }
            
            @Override
            public void onException(Throwable e) {
                log.error("退款消息发送失败,进入重试队列", e);
                retryQueue.add(message);
            }
        }
    );
}

/**
 * 消费退款消息
 */
@RocketMQMessageListener(
    topic = "REFUND_TOPIC",
    consumerGroup = "refund_consumer_group"
)
public class RefundConsumer implements RocketMQListener<RefundMessage> {
    @Override
    public void onMessage(RefundMessage message) {
        // 调用支付系统退款接口
        paymentService.refund(message);
    }
}
}

七、运行验证

1. 创建测试拼团

GroupCreateRequest request = new GroupCreateRequest();
request.setDuration(24); // 24小时有效期
groupService.createGroup(request);

// 生成的拼团示例:
// ID: 7837264872346723(雪花ID)
// process_slot: 123(根据CRC32计算)
// expire_time: 创建时间+24小时

2. 查看定时任务日志

Logs for processing group in slot 84:
- Start processing group in slot 84: 2024-04-25 14:10:00 [group-process-1] INFO
- Batch update of 500 group statuses: 2024-04-25 14:10:02 [group-process-1] INFO
- Successful sending of refund message for 500 groups: 2024-04-25 14:10:05 [group-process-1] INFO

3. 数据库状态变化

idprocess_slotstatusexpire_time
783726487234672384PROCESSING2024-04-25 13:00:00

提示:完整运行需要以下中间件:

  1. MySQL 5.7+
  2. Redis 5.0+
  3. RocketMQ 4.9+

建议使用Docker快速搭建测试环境

最后说明

采用crc32计算原因:
性能与均衡性的最佳平衡:相比MD5/SHA等加密哈希速度更快,比原生hashCode分布更均匀.

# 生鲜集市小程序商城开发模板 ## 一、项目概述 “生鲜集市”小程序商城旨在为用户提供便捷的生鲜采购平台,涵盖丰富的生鲜品类,确保新鲜、优质的商品供应。通过简洁易用的界面设计和高效的购物流程,提升用户购物体验,同时为商家提供全面的订单管理和数据分析功能,助力业务增长。 ## 二、功能模块 ### (一)用户端 1. **商品展示**:以图文形式展示各类生鲜商品,包括水果、蔬菜、肉类、海鲜等,按分类浏览,支持搜索功能,方便用户查找所需商品。提供商品详情页,展示商品规格、产地、保质期、营养成分等信息。 2. **购物车**:用户可将心仪商品加入购物车,在购物车中调整商品数量、选择商品进行结算,支持批量删除商品。显示购物车商品总价,结算时自动计算运费(若有)。 3. **订单管理**:用户可查看所有订单,包括待付款、待发货、运输中、已完成、已取消等状态。对未付款订单进行支付操作,对已发货订单查看物流信息,对已完成订单进行评价。 4. **个人中心**:展示用户基本信息,如头像、昵称、手机号,支持修改个人信息。显示用户积分、优惠券、收藏的商品和店铺。提供收货地址管理功能,包括添加、修改、删除地址,设置默认收货地址。支持账户安全设置,如修改密码、绑定第三方账号。 ### (二)商家端 1. **商品管理**:添加、编辑、删除商品信息,包括商品名称、价格、库存、图片、详情描述等。设置商品分类、标签,便于用户筛选。实时查看商品销量、库存预警,及时补货或调整商品策略。 2. **订单管理**:查看所有订单详情,包括订单编号、下单时间、用户信息、商品信息、订单状态等。对订单进行发货操作,填写物流单号;处理售后订单,如退款、换货申请。 3. **数据统计**:分析商品销售数据,如销量、销售额、订单量等,按日、周、月查看趋势图表。查看用户行为数据,如访问量、浏览量、购买转化率,优化商品展示和营销策略。 ### (三)后台管理 1. **用户管理**:查看所有用户信息,包括基本信息、账户状态、消费记录等。对违规用户进行封禁、限制操作,保障平台秩序。 2. **商品管理**:审核商家提交的商品信息,确保商品合规、质量达标。对商品进行上下架管理,维护平台商品展示。 3. **订单管理**:监控平台所有订单,处理异常订单,如支付异常、物流异常等。统计订单数据,为运营决策提供支持。 4. **数据统计分析**:综合分析平台数据,包括用户增长、商品销售、订单趋势等,生成报表和图表。通过数据挖掘,发现潜在业务机会,优化平台运营策略。 ## 三、页面设计 ### (一)首页 1. **顶部导航栏**:展示小程序名称、搜索框、用户头像(点击可进入个人中心)。 2. **轮播图**:展示热门商品、促销活动等,吸引用户注意力。 3. **商品分类导航**:以图标和文字形式展示各类生鲜商品分类,方便用户快速进入相应分类页面。 4. **热门商品推荐**:展示热门、畅销的生鲜商品,包括商品图片、名称、价格、销量等信息,吸引用户购买。 5. **底部导航栏**:包含“首页”“购物车”“订单”“我的”四个功能模块入口。 ### (二)商品分类页 1. **分类列表**:以列表形式展示所有商品分类,每个分类展示分类名称、图标和分类下商品数量。 2. **商品列表**:进入具体分类后,展示该分类下的商品列表,包括商品图片、名称、价格、销量等信息,支持按销量、价格等排序。 ### (三)商品详情页 1. **商品图片轮播**:展示商品多角度高清图片,让用户全面了解商品外观。 2. **商品基本信息**:显示商品名称、价格、规格、产地、保质期等信息。 3. **商品详情描述**:详细介绍商品的特点、营养价值、食用方法等。 4. **用户评价**:展示其他用户对该商品的评价和评分,帮助用户了解商品口碑。 5. **购买按钮**:包括“加入购物车”“立即购买”按钮,方便用户操作。 ### (四)购物车页 1. **购物车列表**:展示购物车中所有商品,包括商品图片、名称、规格、数量、单价、总价等信息。 2. **商品操作按钮**:支持对商品进行数量增减、删除操作。 3. **全选/反选按钮**:方便用户快速选择或取消选择购物车中的所有商品。 4. **结算按钮**:显示购物车商品总价,点击可进入结算页面。 ### (五)订单页 1. **订单列表**:按订单状态展示所有订单,包括订单编号、下单时间、订单金额、订单状态等信息。 2. **订单详情按钮**:点击可查看订单详细信息,包括商品信息、收货地址、支付方式等。 ### (六)个人中心页 1. **个人信息展示区**:展示用户头像、昵称、手机号,提供“编辑资料”按钮。 2. **功能模块入口**:包括“我的订单”“我的
03-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@淡 定

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

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

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

打赏作者

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

抵扣说明:

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

余额充值