在工厂建模系统中,版本管理是一个核心需求。本文将介绍如何基于MySQL 5.7的JSON字段存储和JDK 1.8实现工厂建模数据的版本对比功能。
技术栈概述
- MySQL 5.7+: 支持原生JSON数据类型和JSON相关函数
- JDK 1.8: 提供Lambda表达式和Stream API,简化集合操作
- JSON处理: 使用Jackson或Gson库进行JSON序列化/反序列化
数据库设计
工厂建模表结构
CREATE TABLE factory_model (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
model_name VARCHAR(100) NOT NULL COMMENT '模型名称',
version INT NOT NULL DEFAULT 1 COMMENT '版本号',
model_data JSON NOT NULL COMMENT '模型数据(JSON格式)',
description TEXT COMMENT '版本描述',
created_by VARCHAR(50) NOT NULL,
created_time DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_model_version (model_name, version)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工厂建模表';
模型数据JSON结构示例
{
"factory": {
"name": "智能工厂A",
"type": "AUTO_ASSEMBLY",
"area": 5000
},
"productionLines": [
{
"id": "line-001",
"name": "组装线1",
"machines": [
{
"id": "machine-001",
"type": "ROBOT_ARM",
"specifications": {
"maxLoad": 50,
"precision": 0.01
}
}
]
}
],
"layout": {
"width": 100,
"height": 50,
"units": []
}
}
核心实现代码
1. 模型实体类
public class FactoryModel {
private Long id;
private String modelName;
private Integer version;
private String modelData; // JSON字符串
private String description;
private String createdBy;
private Date createdTime;
private Date updatedTime;
// getters and setters
}
2. JSON数据对应的Java对象
public class ModelData {
private FactoryInfo factory;
private List<ProductionLine> productionLines;
private Layout layout;
// 静态内部类定义
public static class FactoryInfo {
private String name;
private String type;
private Double area;
// getters and setters
}
public static class ProductionLine {
private String id;
private String name;
private List<Machine> machines;
// getters and setters
}
public static class Machine {
private String id;
private String type;
private Specifications specifications;
// getters and setters
}
public static class Specifications {
private Double maxLoad;
private Double precision;
// getters and setters
}
public static class Layout {
private Integer width;
private Integer height;
private List<LayoutUnit> units;
// getters and setters
}
// getters and setters
}
3. 版本对比结果对象
public class VersionComparison {
private String modelName;
private Integer baseVersion;
private Integer targetVersion;
private List<Difference> differences;
private Date compareTime;
public static class Difference {
private String path; // JSON路径,如 "factory.name"
private ChangeType changeType; // ADD, DELETE, MODIFY
private Object oldValue;
private Object newValue;
private String description;
public enum ChangeType {
ADD, DELETE, MODIFY
}
// getters and setters
}
// getters and setters
}
4. 版本对比服务实现
@Service
public class ModelVersionService {
@Autowired
private FactoryModelMapper modelMapper;
private ObjectMapper objectMapper = new ObjectMapper();
/**
* 对比两个版本的模型数据
*/
public VersionComparison compareVersions(String modelName, Integer version1, Integer version2) {
FactoryModel model1 = modelMapper.selectByModelAndVersion(modelName, version1);
FactoryModel model2 = modelMapper.selectByModelAndVersion(modelName, version2);
if (model1 == null || model2 == null) {
throw new RuntimeException("指定版本的模型不存在");
}
try {
ModelData data1 = objectMapper.readValue(model1.getModelData(), ModelData.class);
ModelData data2 = objectMapper.readValue(model2.getModelData(), ModelData.class);
return compareModelData(data1, data2, version1, version2, modelName);
} catch (Exception e) {
throw new RuntimeException("模型数据解析失败", e);
}
}
/**
* 递归对比模型数据
*/
private VersionComparison compareModelData(ModelData data1, ModelData data2,
Integer baseVersion, Integer targetVersion,
String modelName) {
VersionComparison comparison = new VersionComparison();
comparison.setModelName(modelName);
comparison.setBaseVersion(baseVersion);
comparison.setTargetVersion(targetVersion);
comparison.setCompareTime(new Date());
List<VersionComparison.Difference> differences = new ArrayList<>();
// 对比工厂基本信息
compareFactoryInfo(data1.getFactory(), data2.getFactory(), "factory", differences);
// 对比生产线
compareProductionLines(data1.getProductionLines(), data2.getProductionLines(),
"productionLines", differences);
// 对比布局
compareLayout(data1.getLayout(), data2.getLayout(), "layout", differences);
comparison.setDifferences(differences);
return comparison;
}
private void compareFactoryInfo(ModelData.FactoryInfo info1, ModelData.FactoryInfo info2,
String path, List<VersionComparison.Difference> differences) {
if (info1 == null && info2 == null) return;
if (info1 == null) {
differences.add(createDifference(path, null, info2,
VersionComparison.Difference.ChangeType.ADD));
return;
}
if (info2 == null) {
differences.add(createDifference(path, info1, null,
VersionComparison.Difference.ChangeType.DELETE));
return;
}
compareValue(path + ".name", info1.getName(), info2.getName(), differences);
compareValue(path + ".type", info1.getType(), info2.getType(), differences);
compareValue(path + ".area", info1.getArea(), info2.getArea(), differences);
}
private void compareProductionLines(List<ModelData.ProductionLine> lines1,
List<ModelData.ProductionLine> lines2,
String path, List<VersionComparison.Difference> differences) {
if (lines1 == null) lines1 = new ArrayList<>();
if (lines2 == null) lines2 = new ArrayList<>();
// 使用ID作为标识符进行对比
Map<String, ModelData.ProductionLine> map1 = lines1.stream()
.collect(Collectors.toMap(ModelData.ProductionLine::getId, Function.identity()));
Map<String, ModelData.ProductionLine> map2 = lines2.stream()
.collect(Collectors.toMap(ModelData.ProductionLine::getId, Function.identity()));
// 找出新增的生产线
map2.keySet().stream()
.filter(id -> !map1.containsKey(id))
.forEach(id -> differences.add(createDifference(
path + "[" + id + "]", null, map2.get(id),
VersionComparison.Difference.ChangeType.ADD)));
// 找出删除的生产线
map1.keySet().stream()
.filter(id -> !map2.containsKey(id))
.forEach(id -> differences.add(createDifference(
path + "[" + id + "]", map1.get(id), null,
VersionComparison.Difference.ChangeType.DELETE)));
// 对比共同存在的生产线
map1.keySet().stream()
.filter(map2::containsKey)
.forEach(id -> compareProductionLine(
map1.get(id), map2.get(id), path + "[" + id + "]", differences));
}
private void compareProductionLine(ModelData.ProductionLine line1,
ModelData.ProductionLine line2,
String path, List<VersionComparison.Difference> differences) {
compareValue(path + ".name", line1.getName(), line2.getName(), differences);
// 对比机器设备
compareMachines(line1.getMachines(), line2.getMachines(), path + ".machines", differences);
}
private void compareMachines(List<ModelData.Machine> machines1,
List<ModelData.Machine> machines2,
String path, List<VersionComparison.Difference> differences) {
if (machines1 == null) machines1 = new ArrayList<>();
if (machines2 == null) machines2 = new ArrayList<>();
Map<String, ModelData.Machine> map1 = machines1.stream()
.collect(Collectors.toMap(ModelData.Machine::getId, Function.identity()));
Map<String, ModelData.Machine> map2 = machines2.stream()
.collect(Collectors.toMap(ModelData.Machine::getId, Function.identity()));
// 类似的对比逻辑...
}
private void compareValue(String path, Object oldValue, Object newValue,
List<VersionComparison.Difference> differences) {
if (!Objects.equals(oldValue, newValue)) {
differences.add(createDifference(path, oldValue, newValue,
VersionComparison.Difference.ChangeType.MODIFY));
}
}
private VersionComparison.Difference createDifference(String path, Object oldValue,
Object newValue,
VersionComparison.Difference.ChangeType changeType) {
VersionComparison.Difference diff = new VersionComparison.Difference();
diff.setPath(path);
diff.setOldValue(oldValue);
diff.setNewValue(newValue);
diff.setChangeType(changeType);
// 生成描述信息
String desc = generateDescription(path, oldValue, newValue, changeType);
diff.setDescription(desc);
return diff;
}
private String generateDescription(String path, Object oldValue, Object newValue,
VersionComparison.Difference.ChangeType changeType) {
switch (changeType) {
case ADD:
return String.format("新增 %s: %s", path, newValue);
case DELETE:
return String.format("删除 %s: %s", path, oldValue);
case MODIFY:
return String.format("修改 %s: %s -> %s", path, oldValue, newValue);
default:
return "未知变更";
}
}
}
5. MySQL JSON函数的高级应用
除了基本的存储,MySQL 5.7+ 的JSON函数还可以用于优化查询:
-- 查询包含特定类型机器的版本
SELECT version, model_name
FROM factory_model
WHERE JSON_CONTAINS(model_data, '{"type": "ROBOT_ARM"}', '$.productionLines[*].machines[*]');
-- 查询工厂面积大于特定值的版本
SELECT version, model_name
FROM factory_model
WHERE JSON_EXTRACT(model_data, '$.factory.area') > 3000;
-- 提取所有版本中的机器类型统计
SELECT JSON_EXTRACT(model_data, '$.productionLines[*].machines[*].type') as machine_types
FROM factory_model;
性能优化建议
- JSON路径索引: 对常用的JSON字段创建虚拟列并建立索引
ALTER TABLE factory_model
ADD COLUMN factory_name VARCHAR(100)
GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(model_data, '$.factory.name')));
CREATE INDEX idx_factory_name ON factory_model(factory_name);
-
部分更新: 使用MySQL的JSON_SET等函数进行部分字段更新,减少全量数据写入
-
数据归档: 定期归档旧版本数据,保持主表性能
















