美团买菜商品迭代方案:记录、版本管理、对比回滚及性能优化部署
分类:IT频道
时间:2026-03-06 23:40
浏览:7
概述
一、系统设计目标 1.完整记录商品从上架到下架的全生命周期变更 2.支持商品信息多版本对比和回滚 3.提供高效的查询和审计能力 4.确保数据一致性和可追溯性 二、核心功能模块 1.商品变更记录表设计 ```sql CREATETABLEproduct_chan
内容
一、系统设计目标
1. 完整记录商品从上架到下架的全生命周期变更
2. 支持商品信息多版本对比和回滚
3. 提供高效的查询和审计能力
4. 确保数据一致性和可追溯性
二、核心功能模块
1. 商品变更记录表设计
```sql
CREATE TABLE product_change_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL COMMENT 商品ID,
change_type VARCHAR(20) NOT NULL COMMENT 变更类型(CREATE/UPDATE/DELETE/STATUS_CHANGE),
old_data JSON COMMENT 变更前数据(JSON格式),
new_data JSON NOT NULL COMMENT 变更后数据(JSON格式),
change_field_list VARCHAR(255) COMMENT 变更字段列表(逗号分隔),
operator_id BIGINT COMMENT 操作人ID,
operator_name VARCHAR(50) COMMENT 操作人名称,
operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 操作时间,
client_ip VARCHAR(50) COMMENT 操作IP,
remark VARCHAR(500) COMMENT 变更备注,
INDEX idx_product_id (product_id),
INDEX idx_operation_time (operation_time)
) ENGINE=InnoDB COMMENT=商品变更记录表;
```
2. 商品版本管理表设计
```sql
CREATE TABLE product_version (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL COMMENT 商品ID,
version_no VARCHAR(20) NOT NULL COMMENT 版本号(YYYYMMDD_序号),
version_data JSON NOT NULL COMMENT 版本完整数据,
is_current TINYINT(1) DEFAULT 0 COMMENT 是否当前版本(1是0否),
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,
operator_id BIGINT COMMENT 操作人ID,
operator_name VARCHAR(50) COMMENT 操作人名称,
UNIQUE KEY uk_product_version (product_id, version_no),
INDEX idx_product_id (product_id)
) ENGINE=InnoDB COMMENT=商品版本表;
```
三、关键实现逻辑
1. 商品变更拦截器
```java
@Aspect
@Component
public class ProductChangeAspect {
@Autowired
private ProductChangeLogService changeLogService;
@Autowired
private ProductVersionService versionService;
// 拦截商品创建、更新、删除等方法
@AfterReturning(pointcut = "execution(* com.meituan.buymarket.service.ProductService.*(..)) " +
"&& @annotation(com.meituan.buymarket.annotation.ProductChangeLog)",
returning = "result")
public void afterProductChange(JoinPoint joinPoint, Object result) {
// 获取方法参数
Object[] args = joinPoint.getArgs();
Product product = null;
ChangeLogType changeType = null;
// 根据方法名确定变更类型
String methodName = joinPoint.getSignature().getName();
if (methodName.startsWith("create")) {
product = (Product) args[0];
changeType = ChangeLogType.CREATE;
} else if (methodName.startsWith("update")) {
// 需要比较新旧数据
// ...
changeType = ChangeLogType.UPDATE;
} else if (methodName.startsWith("delete")) {
product = (Product) args[0];
changeType = ChangeLogType.DELETE;
}
// 记录变更日志
changeLogService.recordChange(product, changeType, operatorInfo);
// 创建版本快照
if (changeType == ChangeLogType.CREATE || changeType == ChangeLogType.UPDATE) {
versionService.createVersionSnapshot(product, operatorInfo);
}
}
}
```
2. 变更记录生成服务
```java
@Service
public class ProductChangeLogServiceImpl implements ProductChangeLogService {
@Override
public void recordChange(Product product, ChangeLogType changeType, OperatorInfo operatorInfo) {
ProductChangeLog log = new ProductChangeLog();
log.setProductId(product.getId());
log.setChangeType(changeType.name());
switch (changeType) {
case CREATE:
log.setNewData(JSON.toJSONString(product));
break;
case UPDATE:
// 需要从数据库获取旧数据
Product oldProduct = productRepository.findById(product.getId());
log.setOldData(JSON.toJSONString(oldProduct));
log.setNewData(JSON.toJSONString(product));
// 计算变更字段
Set changedFields = calculateChangedFields(oldProduct, product);
log.setChangeFieldList(String.join(",", changedFields));
break;
case DELETE:
// 获取旧数据
Product deleteProduct = productRepository.findById(product.getId());
log.setOldData(JSON.toJSONString(deleteProduct));
break;
}
// 设置操作人信息
if (operatorInfo != null) {
log.setOperatorId(operatorInfo.getOperatorId());
log.setOperatorName(operatorInfo.getOperatorName());
log.setClientIp(operatorInfo.getClientIp());
}
productChangeLogRepository.save(log);
}
private Set calculateChangedFields(Product oldProduct, Product newProduct) {
// 实现字段差异比较逻辑
// ...
}
}
```
3. 版本管理服务
```java
@Service
public class ProductVersionServiceImpl implements ProductVersionService {
@Override
public void createVersionSnapshot(Product product, OperatorInfo operatorInfo) {
// 生成版本号
String versionNo = generateVersionNo();
// 创建版本记录
ProductVersion version = new ProductVersion();
version.setProductId(product.getId());
version.setVersionNo(versionNo);
version.setVersionData(JSON.toJSONString(product));
version.setIsCurrent(true);
if (operatorInfo != null) {
version.setOperatorId(operatorInfo.getOperatorId());
version.setOperatorName(operatorInfo.getOperatorName());
}
productVersionRepository.save(version);
// 更新旧版本为非当前版本
productVersionRepository.updateOtherVersionsToNonCurrent(product.getId(), versionNo);
}
private String generateVersionNo() {
// 生成格式为YYYYMMDD_序号的版本号
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String datePart = sdf.format(new Date());
// 查询当天已生成的版本数量
long count = productVersionRepository.countTodayVersions();
return datePart + "_" + (count + 1);
}
}
```
四、高级功能实现
1. 商品变更对比功能
```java
@Service
public class ProductCompareServiceImpl implements ProductCompareService {
@Override
public CompareResult compareVersions(Long productId, String version1, String version2) {
// 获取两个版本的数据
ProductVersion v1 = productVersionRepository.findByProductIdAndVersionNo(productId, version1);
ProductVersion v2 = productVersionRepository.findByProductIdAndVersionNo(productId, version2);
CompareResult result = new CompareResult();
result.setProductId(productId);
result.setVersion1(version1);
result.setVersion2(version2);
// 解析JSON数据
Map data1 = JSON.parseObject(v1.getVersionData(), Map.class);
Map data2 = JSON.parseObject(v2.getVersionData(), Map.class);
// 比较差异
List differences = new ArrayList<>();
// 比较所有字段
for (String field : ALL_PRODUCT_FIELDS) {
Object value1 = data1.get(field);
Object value2 = data2.get(field);
if (!Objects.equals(value1, value2)) {
FieldDifference diff = new FieldDifference();
diff.setFieldName(field);
diff.setOldValue(value1 != null ? value1.toString() : null);
diff.setNewValue(value2 != null ? value2.toString() : null);
differences.add(diff);
}
}
result.setDifferences(differences);
return result;
}
}
```
2. 商品回滚功能
```java
@Service
public class ProductRollbackServiceImpl implements ProductRollbackService {
@Autowired
private ProductService productService;
@Autowired
private ProductVersionService versionService;
@Override
public boolean rollbackToVersion(Long productId, String targetVersion, OperatorInfo operatorInfo) {
// 获取目标版本数据
ProductVersion targetVersionData = versionService.getVersionByNo(productId, targetVersion);
if (targetVersionData == null) {
throw new BusinessException("目标版本不存在");
}
// 解析版本数据
Product product = JSON.parseObject(targetVersionData.getVersionData(), Product.class);
product.setId(productId); // 确保ID正确
// 执行更新操作
try {
productService.updateProduct(product, operatorInfo);
// 记录回滚操作日志
ProductChangeLog log = new ProductChangeLog();
log.setProductId(productId);
log.setChangeType(ChangeLogType.ROLLBACK.name());
log.setNewData(JSON.toJSONString(product));
log.setRemark("回滚到版本: " + targetVersion);
// 设置操作人信息...
productChangeLogRepository.save(log);
return true;
} catch (Exception e) {
log.error("回滚失败", e);
throw new BusinessException("回滚操作失败");
}
}
}
```
五、性能优化方案
1. 异步记录变更日志:使用消息队列异步处理变更日志记录
2. 批量插入优化:对于高频变更的商品,采用批量插入变更日志
3. 数据归档策略:定期归档历史变更记录到冷存储
4. 缓存热点数据:对频繁查询的商品版本数据进行缓存
5. 读写分离:变更日志查询走从库,减轻主库压力
六、监控与告警
1. 变更频率监控:监控商品变更频率,异常时告警
2. 变更失败监控:监控变更日志记录失败情况
3. 版本数量监控:监控单个商品版本数量,过多时告警
4. 操作人监控:监控特定操作人的高频变更行为
七、部署方案
1. 独立数据库:变更记录和版本数据建议使用独立数据库
2. 分库分表:对于大规模系统,可按商品ID分库分表
3. 读写分离:查询和写入分离,提高系统吞吐量
4. 备份策略:定期备份变更记录和版本数据
此方案实现了美团买菜系统商品迭代记录的完整功能,包括变更记录、版本管理、对比回滚等核心功能,同时考虑了性能优化和系统稳定性。
评论