CREATE TABLE `ylt-mall-new`.`Untitled` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '配置ID', `level` tinyint NOT NULL COMMENT '会员等级', `first_level_rate` decimal(5, 2) NOT NULL COMMENT '一级分销提成比例(%)', `second_level_rate` decimal(5, 2) NOT NULL COMMENT '二级分销提成比例(%)', `min_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '最低提现金额', `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态(1-启用,0-禁用)', `create_by` bigint NULL DEFAULT NULL COMMENT '创建者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_by` bigint NULL DEFAULT NULL COMMENT '更新者', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `uk_level`(`level` ASC) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '提成配置表' ROW_FORMAT = Dynamic;
时间: 2025-08-21 19:06:21 AIGC 浏览: 26
<think>根据用户提供的提成配置表结构,我们需要实现一个分销逻辑,即根据会员等级配置的一级和二级分销比例,计算订单的分销佣金。以下是实现步骤:
### 1. 数据库表结构分析
用户提供的表结构为`ylt-mall-new`.`Untitled`(我们将其命名为`commission_config`):
```sql
CREATE TABLE `commission_config` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '配置ID',
`level` tinyint NOT NULL COMMENT '会员等级',
`first_level_rate` decimal(5, 2) NOT NULL COMMENT '一级分销提成比例(%)',
`second_level_rate` decimal(5, 2) NOT NULL COMMENT '二级分销提成比例(%)',
`min_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '最低提现金额',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态(1-启用,0-禁用)',
`create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE INDEX `uk_level`(`level`)
) COMMENT = '提成配置表';
```
### 2. 分销逻辑设计
- 当用户下单时,我们需要根据购买者的会员等级(对应配置表中的`level`)获取分销比例。
- 分销佣金分为两级:
- 一级分销:直接推荐人,按`first_level_rate`计算
- 二级分销:间接推荐人(推荐人的推荐人),按`second_level_rate`计算
- 注意:配置表中`first_level_rate`和`second_level_rate`是百分比,例如10%则存储为10.00。
### 3. Java代码实现
#### 3.1 实体类定义
```java
// 提成配置实体
@Data
public class CommissionConfig {
private Long id;
private Integer level; // 会员等级
private BigDecimal firstLevelRate; // 一级分销比例(%)
private BigDecimal secondLevelRate; // 二级分销比例(%)
private BigDecimal minAmount; // 最低提现金额
private Integer status; // 状态:1启用,0禁用
private Long createBy;
private Date createTime;
private Long updateBy;
private Date updateTime;
private Integer deleted;
}
// 订单实体
@Data
public class Order {
private Long id;
private BigDecimal totalAmount; // 订单总金额
private Long userId; // 下单用户ID
private Integer userLevel; // 下单用户的会员等级
// 其他字段...
}
// 分销记录实体
@Data
public class DistributionRecord {
private Long id;
private Long orderId; // 订单ID
private Long promoterId; // 分销商ID(一级或二级)
private Integer level; // 分销级别:1-一级,2-二级
private BigDecimal commission; // 佣金金额
private Date createTime;
}
```
#### 3.2 分销服务实现
```java
@Service
@RequiredArgsConstructor
public class DistributionService {
private final CommissionConfigMapper configMapper;
private final DistributionRecordMapper recordMapper;
private final UserService userService; // 用于获取用户的分销关系
/**
* 处理订单的分销佣金
* @param order 订单
*/
@Transactional
public void processDistribution(Order order) {
// 1. 根据订单中的用户等级获取提成配置
CommissionConfig config = configMapper.selectByLevel(order.getUserLevel());
if (config == null || config.getStatus() != 1) {
// 没有找到配置或配置禁用,不处理分销
return;
}
// 2. 获取该用户的分销关系(一级和二级推荐人)
Map<Integer, Long> promoters = userService.getPromotersByUserId(order.getUserId());
if (promoters.isEmpty()) {
return; // 没有分销关系
}
// 3. 计算一级分销佣金
if (promoters.containsKey(1)) {
BigDecimal commission = calculateCommission(order.getTotalAmount(), config.getFirstLevelRate());
saveDistributionRecord(order.getId(), promoters.get(1), 1, commission);
}
// 4. 计算二级分销佣金
if (promoters.containsKey(2)) {
BigDecimal commission = calculateCommission(order.getTotalAmount(), config.getSecondLevelRate());
saveDistributionRecord(order.getId(), promoters.get(2), 2, commission);
}
}
// 计算佣金:订单金额 * (比例/100)
private BigDecimal calculateCommission(BigDecimal orderAmount, BigDecimal rate) {
return orderAmount.multiply(rate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
}
// 保存分销记录
private void saveDistributionRecord(Long orderId, Long promoterId, int level, BigDecimal commission) {
DistributionRecord record = new DistributionRecord();
record.setOrderId(orderId);
record.setPromoterId(promoterId);
record.setLevel(level);
record.setCommission(commission);
record.setCreateTime(new Date());
recordMapper.insert(record);
}
}
```
#### 3.3 Mapper接口
```java
@Mapper
public interface CommissionConfigMapper {
// 根据会员等级获取配置
@Select("SELECT * FROM commission_config WHERE level = #{level} AND deleted = 0")
CommissionConfig selectByLevel(Integer level);
}
@Mapper
public interface DistributionRecordMapper {
@Insert("INSERT INTO distribution_record(order_id, promoter_id, level, commission, create_time) " +
"VALUES(#{orderId}, #{promoterId}, #{level}, #{commission}, #{createTime})")
void insert(DistributionRecord record);
}
```
#### 3.4 用户服务接口(获取分销关系)
```java
public interface UserService {
/**
* 根据用户ID获取其上级分销商
* @param userId 用户ID
* @return 分销商映射,key为分销层级(1-一级,2-二级),value为分销商ID
*/
Map<Integer, Long> getPromotersByUserId(Long userId);
}
```
### 4. 注意事项
1. **佣金计算精度**:使用`BigDecimal`进行精确计算,避免浮点数精度问题。
2. **事务管理**:使用`@Transactional`确保分销记录和订单状态的一致性。
3. **配置状态检查**:只有状态为1(启用)的配置才生效。
4. **分销关系获取**:需要根据业务逻辑实现`UserService.getPromotersByUserId`,从用户表中获取上级分销商。
### 5. 示例调用
```java
// 假设有一个订单
Order order = new Order();
order.setId(10001L);
order.setTotalAmount(new BigDecimal("100.00"));
order.setUserId(20001L);
order.setUserLevel(2); // 会员等级为2
// 调用分销处理
distributionService.processDistribution(order);
```
### 6. 高级考虑
- **性能优化**:如果订单量很大,可以考虑异步处理分销逻辑,使用消息队列。
- **防重处理**:在分销记录表中,可以为`(order_id, level)`添加唯一索引,防止重复计算。
- **配置缓存**:提成配置不经常变动,可以缓存到内存中(如使用Caffeine或Redis)。
### 7. 相关问题
§§相关问题§§
1. 如何实现分销配置的动态更新和实时生效?
2. 多级分销中跨级佣金分配如何处理更合理?
3. 分销佣金结算时如何保证事务和数据的强一致性?
4. 分销关系链断裂时应该采用什么补偿策略?
5. 如何设计高并发场景下的分销记录批量处理方案?</think>根据您提供的提成配置表结构,我将实现一个完整的Java分销逻辑解决方案。这个方案包含实体类、服务层逻辑、佣金计算和分销记录生成。
### 1. 实体类定义(对应数据库表)
```java
// 提成配置实体
@Data
public class CommissionConfig {
private Long id; // 配置ID
private Integer level; // 会员等级
private BigDecimal firstLevelRate; // 一级分销比例(%)
private BigDecimal secondLevelRate; // 二级分销比例(%)
private BigDecimal minAmount; // 最低提现金额
private Integer status; // 状态(1-启用,0-禁用)
private Long createBy;
private Date createTime;
private Long updateBy;
private Date updateTime;
private Integer deleted;
}
// 分销记录实体
@Data
public class DistributionRecord {
private Long id;
private Long orderId; // 关联订单ID
private Long promoterId; // 分销商ID
private Integer level; // 分销层级(1-一级,2-二级)
private BigDecimal commission; // 佣金金额
private Date createTime;
}
// 订单实体
@Data
public class Order {
private Long id;
private BigDecimal amount; // 订单金额
private Long userId; // 下单用户ID
private Integer userLevel; // 用户会员等级
private Date createTime;
}
// 分销关系实体
@Data
public class DistributionRelation {
private Long userId;
private Long firstLevelPromoter; // 一级分销商ID
private Long secondLevelPromoter; // 二级分销商ID
}
```
### 2. 分销服务实现
```java
@Service
@RequiredArgsConstructor
public class DistributionService {
private final CommissionConfigMapper configMapper;
private final DistributionRecordMapper recordMapper;
private final UserService userService;
/**
* 处理订单分销逻辑
* @param order 订单信息
*/
@Transactional
public void processOrderDistribution(Order order) {
// 1. 获取用户的会员等级配置
CommissionConfig config = configMapper.selectByLevel(order.getUserLevel());
if (config == null || config.getStatus() != 1) {
return; // 配置不存在或已禁用
}
// 2. 获取用户的分销关系链
DistributionRelation relation = userService.getDistributionRelation(order.getUserId());
if (relation == null) return;
List<DistributionRecord> records = new ArrayList<>();
// 3. 计算一级分销佣金
if (relation.getFirstLevelPromoter() != null) {
BigDecimal commission = calculateCommission(
order.getAmount(),
config.getFirstLevelRate()
);
records.add(createRecord(order, relation.getFirstLevelPromoter(), 1, commission));
}
// 4. 计算二级分销佣金
if (relation.getSecondLevelPromoter() != null) {
BigDecimal commission = calculateCommission(
order.getAmount(),
config.getSecondLevelRate()
);
records.add(createRecord(order, relation.getSecondLevelPromoter(), 2, commission));
}
// 5. 保存分销记录
if (!records.isEmpty()) {
recordMapper.batchInsert(records);
}
}
/**
* 计算分销佣金
* @param orderAmount 订单金额
* @param rate 提成比例(%)
* @return 佣金金额
*/
private BigDecimal calculateCommission(BigDecimal orderAmount, BigDecimal rate) {
// 佣金 = 订单金额 × (提成比例/100)
return orderAmount.multiply(rate)
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
}
/**
* 创建分销记录
*/
private DistributionRecord createRecord(Order order, Long promoterId,
int level, BigDecimal commission) {
DistributionRecord record = new DistributionRecord();
record.setOrderId(order.getId());
record.setPromoterId(promoterId);
record.setLevel(level);
record.setCommission(commission);
record.setCreateTime(new Date());
return record;
}
}
```
### 3. MyBatis Mapper接口
```java
@Mapper
public interface CommissionConfigMapper {
// 根据会员等级获取配置
@Select("SELECT * FROM commission_config " +
"WHERE level = #{level} AND status = 1 AND deleted = 0")
CommissionConfig selectByLevel(Integer level);
}
@Mapper
public interface DistributionRecordMapper {
// 批量插入分销记录
@Insert("<script>" +
"INSERT INTO distribution_record(order_id, promoter_id, level, commission, create_time) " +
"VALUES " +
"<foreach collection='list' item='record' separator=','>" +
"(#{record.orderId}, #{record.promoterId}, #{record.level}, #{record.commission}, #{record.createTime})" +
"</foreach>" +
"</script>")
@Options(useGeneratedKeys = true, keyProperty = "id")
void batchInsert(List<DistributionRecord> records);
// 检查订单是否已处理过分销
@Select("SELECT COUNT(*) FROM distribution_record WHERE order_id = #{orderId}")
boolean existsByOrderId(Long orderId);
}
```
### 4. 分销关系服务
```java
public interface UserService {
/**
* 获取用户的分销关系链
* @param userId 用户ID
* @return 分销关系对象
*/
DistributionRelation getDistributionRelation(Long userId);
}
```
### 5. 佣金计算公式
分销佣金计算公式为:
$$ \text{佣金} = \text{订单金额} \times \frac{\text{提成比例}}{100} $$
例如:
- 订单金额 = ¥1000.00
- 一级提成比例 = 10%
- 一级佣金 = $1000 \times \frac{10}{100} = ¥100.00$
### 6. 防重处理(AOP切面)
```java
@Aspect
@Component
public class DistributionAspect {
private final DistributionRecordMapper recordMapper;
// 防止重复处理订单
@Around("execution(* com.example.service.DistributionService.processOrderDistribution(..))")
public Object checkDuplicate(ProceedingJoinPoint joinPoint) throws Throwable {
Order order = (Order) joinPoint.getArgs()[0];
if (recordMapper.existsByOrderId(order.getId())) {
throw new DuplicateProcessingException("订单已处理过分销: " + order.getId());
}
return joinPoint.proceed();
}
}
```
### 7. 使用示例
```java
// 创建测试订单
Order order = new Order();
order.setId(10001L);
order.setAmount(new BigDecimal("999.00"));
order.setUserId(20001L);
order.setUserLevel(2); // 黄金会员
// 执行分销处理
distributionService.processOrderDistribution(order);
```
### 8. 高级特性实现
#### 8.1 配置缓存(使用Caffeine)
```java
@Cacheable(value = "commissionConfig", key = "#level")
public CommissionConfig getConfigByLevel(Integer level) {
return configMapper.selectByLevel(level);
}
```
#### 8.2 异步处理
```java
@Async
public void asyncProcessOrder(Order order) {
processOrderDistribution(order);
}
```
#### 8.3 事务补偿机制
```java
// 重试机制(使用Spring Retry)
@Retryable(value = SQLException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000))
@Transactional
public void processWithRetry(Order order) {
processOrderDistribution(order);
}
```
### 9. 关键注意事项
1. **金额精度处理**:所有金额计算使用`BigDecimal`并设置精度
```java
amount.setScale(2, RoundingMode.HALF_UP)
```
2. **并发控制**:数据库添加唯一索引
```sql
ALTER TABLE distribution_record ADD UNIQUE uniq_order_level (order_id, level);
```
3. **配置验证**:
```java
private void validateConfig(CommissionConfig config) {
if (config.getFirstLevelRate().compareTo(BigDecimal.ZERO) < 0 ||
config.getFirstLevelRate().compareTo(new BigDecimal("100")) > 0) {
throw new InvalidConfigException("一级分销比例必须在0-100之间");
}
}
```
4. **性能优化**:批量处理订单时使用Spring Batch框架
### 10. 分销流程示意图
```mermaid
graph TD
A[接收订单] --> B{配置有效?}
B -->|是| C[获取分销关系]
B -->|否| D[结束处理]
C --> E{有一级分销?}
E -->|是| F[计算一级佣金]
C --> G{有二级分销?}
G -->|是| H[计算二级佣金]
F --> I[生成分销记录]
H --> I
I --> J[批量保存记录]
```
这个实现完整覆盖了分销配置表的使用场景,包括佣金计算、多级分销处理和记录生成,同时考虑了事务一致性、并发控制和性能优化。
阅读全文
相关推荐








