贝利信息

mysql如何实现积分系统设计_mysql业务项目解析

日期:2026-01-05 00:00 / 作者:P粉602998670
积分变更必须用事务包裹并配合乐观锁,流水表需含trace_id、前后余额等字段,Redis缓存余额并异步双写,过期清理须分批避峰。

积分增减必须用事务包裹,否则并发写入会丢分

用户做签到、下单、评价等行为时,积分变动常伴随其他业务操作(如更新订单状态)。若不加事务,高并发下 SELECT ... FOR UPDATE 缺失或 UPDATE 未隔离,会出现超发或漏扣。比如两个线程同时读取用户当前积分为 100,各自加 10 后写回 110,实际应为 120。

积分流水表要带业务单号+类型+幂等键,不可只存净变化

单纯记录“+10 分”无法追溯来源,也无法对账或回滚。每条积分变动必须对应一次明确的业务动作,并支持重放与校验。

CREATE TABLE point_log (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT NOT NULL,
  order_no VARCHAR(64) DEFAULT '',
  type TINYINT NOT NULL COMMENT '1=签到,2=支付,3=退款,4=后台调整',
  amount INT NOT NULL,
  before_balance INT NOT NULL,
  after_balance INT NOT NULL,
  trace_id VARCHAR(128) NOT NULL UNIQUE,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_user_created (user_id, created_at),
  INDEX idx_trace (trace_id)
) ENGINE=InnoDB;

余额查询不能直连主库,要用缓存兜底+异步双写

用户首页频繁查积分,若每次都查 user_points 表,主库压力大,且一旦慢查询拖垮连接池,整个登录链路都会卡住。

过期积分要分批清理,别用 DELETE FROM ... WHERE expired_at

全表扫描删过期积分,锁表时间长、IO 压力大,高峰期可能直接拖垮主库。

真实项目里最常被忽略的是流水表的 trace_id 设计和 Redis 回填时的并发竞争——这两处出问题,基本意味着积分对不上,而且很难定位。