前言

积分系统设计通常会为用户的积分设置一个有效期,以此提升用户活跃度。例如,2025年1月2日添加的积分记录将在2026年1月2日自动过期。积分项目在处理带有效期的积分时,通过新增"用户当前可用积分明细表"分离积分明细与可用额度。积分过期时,删除可用积分表中的过期记录,并在用户积分流水表中添加过期记录,更新总额表。消费时,优先使用即将过期的积分,按过期时间排序并累加,不足时拆分记录。此方案有效解决积分过期与使用优先级问题,确保数据准确性和用户体验。
数据模型设计
-
需要明确定义用户实体和积分实体的数据结构
-
**积分过期机制:**设计合理的积分时效计算和状态更新规则
-
**存储与查询优化:**规划高效的数据存储方案,并优化过期积分的查询性能
-
**定时任务实现:**开发自动执行积分过期处理的定时调度功能
积分表设计
-
积分优先扣除最早过期的且小面值的积分
-
每天需要定时扫码可用积分表,将过期积分删除,并在积分记录表标注好过期记录以及扣减积分详情表记录扣减值
-
积分总额可直接根据可用积分值计算(即使过期积分没即使删除,也可以通过计算过滤来实现)
我们设计三张表,分布是:用户积分总表 user_point,用户积分流水表 user_point_flow_log,用户当前可用积分明细表 user_point_detail。
user_point 用户积分总表
|---------------|--------|---------------------|
| 字段 | 类型 | 描述 |
| id | BIGINT | 主键 |
| user_id | BIGINT | 用户ID |
| total_balance | INT | 总积分 |
| version | INT | 版本号,Optimistic_Lock |
|----|---------|---------------|---------|
| id | user_id | total_balance | version |
| 1 | 1201 | 20 | 1 |
| 2 | 1202 | 200 | 1 |
user_point_flow_log 用户积分流水表:需要将内容展示给用户,让用户知道自己积分的添加、消耗情况。
| 字段 | 类型 | 描述 |
|---|---|---|
| id | BIGINT | 主键,流水号ID |
| user_id | BIGINT | 用户ID |
| type | INT | 积分记录类型 |
| amount | INT | 积分 |
| action | INT | 动作 1: 增加 2:扣减 |
| expire_time | DATETIME | 过期时间 |
| create_time | DATETIME | 创建时间 |
| remark | Varchar(64) | 备注 |
|----|---------|------|--------|--------|-------------|-------------|--------|
| id | user_id | type | amount | action | expire_time | create_time | remark |
| 1 | 1201 | 1 | 10 | 1 | 2026-12-31 | 2025-12-31 | 签到 |
| 2 | 1201 | 1 | 10 | 1 | 2027-01-01 | 2026-01-01 | 签到 |
| 3 | 1201 | 2 | 10 | 2 | 2026-02-24 | 2026-02-24 | 看剧消耗 |
user_point_detail 当前可用积分明细表 :此表对应的是可用的积分记录,当前积分根据此表值计算得出
| 字段 | 类型 | 描述 |
|---|---|---|
| id | BIGINT | 主键ID |
| user_id | BIGINT | 用户ID |
| balance | INT | 积分 |
| expire_time | DATETIME | 过期时间 |
| create_time | DATETIME | 创建时间 |
| deleted | TINYINT | 删除标记 |
|-----|---------|---------|-------------|-------------|---------|
| id | user_id | balance | expire_time | create_time | deleted |
| 100 | 1201 | 10 | 2026-12-31 | 2025-12-31 | 1 |
| 101 | 1201 | 10 | 2027-01-01 | 2026-01-01 | 0 |
积分过期时,当前可用积分明细表删除过期记录,用户积分流水表添加一条过期明细,积分总额表更新为当前积分总额。
那么积分过期在什么时候触发呢?可以有以下方案:
- 可以每天定时进行一次,对所有的会员操作积分过期计算;
- 用户当天首次登录时,进行积分计算,排除过期积分;
- 每天定时扫描可用积分表1次,将过期积分删除,并及时更新会员积分总额。
第一种方案需要全部遍历会员表,如果会员表太大,效率低下,而且如果会员并没有过期积分,会做许多无效的统计。第二种方案采用被动触发的形式,虽然也会有无效的积分统计,未能及时清理过期积分,但避免了积分的会员表的全表扫描,性能略高。第三种方案从过期积分入手,主动触发,能及时清理过期积分,只针对过期积分,没有无效的统计,性能优于前两种。
积分使用
积分使用策略如下:
- 现在要冻结point个积分
- 将
可用积分表的可用积分记录按过期时间升序排列,依次累加积分额度sumPoint直到sumPoint>=point或记录全部遍历完,用recordIds记录符合要求的积分id,用targetRecord记录最后一条积分记录。 - 判断sumPoint与point大小,若:
- sumPoint < point,则表明用户积分不足,返回false;
- sumPoint = point,则表明当前记录刚好等于消耗记录,进行下一步;
- sumPoint > point,则表明最后一条记录大于积分额度,需要将其拆分成两条记录,一条用于抵扣(recordId不变,积分额度为
(sumPoint-point)),另一条记录积分剩余(额度为最后一条记录的额度-(sumPoint-point),过期时间为最后一条记录的过期时间)。
- 处理可用积分表中的记录、积分明细表记录、积分总额。
积分到期提醒
5亿用户的表,积分到期设计,通过大数据计算积分到期的用户,发送MQ,通过消费MQ发送短信提醒用户。
