需求:API接口--【SaaS后臺(tái)】增加數(shù)據(jù)操作日志記錄
目前做的
實(shí)現(xiàn)過程
1.service中調(diào)用
- 異步處理數(shù)據(jù)及存儲(chǔ)
2.1數(shù)據(jù)處理(展示替換)
2.2數(shù)據(jù)處理(數(shù)據(jù)對(duì)比)
/**
* 對(duì)比節(jié)點(diǎn)數(shù)據(jù)
*
* @param oldNode 舊節(jié)點(diǎn)數(shù)據(jù)
* @param newNode 新節(jié)點(diǎn)數(shù)據(jù)
* @param operationDetails 操作詳情列表
*/
private void compareJsonNodes(JsonNode oldNode, JsonNode newNode, List<OperationDetails> operationDetails) {
// 檢查兩個(gè)節(jié)點(diǎn)是否都是數(shù)組
if (oldNode.isArray() && newNode.isArray()) {
int minSize = Math.min(oldNode.size(), newNode.size());
for (int i = 0; i < minSize; i++) {
compareJsonNodes(oldNode.get(i), newNode.get(i), operationDetails);
}
for (int i = minSize; i < oldNode.size(); i++) {
compareJsonNodes(oldNode.get(i), createEmptyNode(oldNode.get(i)), operationDetails);
}
for (int i = minSize; i < newNode.size(); i++) {
compareJsonNodes(createEmptyNode(newNode.get(i)), newNode.get(i), operationDetails);
}
return;
}
List<SysOperationLogTrackEnum> childNodes = getChildNodes();
Iterator<Map.Entry<String, JsonNode>> newFields = newNode.fields();
// 處理新數(shù)據(jù)中的字段
while (newFields.hasNext()) {
Map.Entry<String, JsonNode> entry = newFields.next();
String fieldName = entry.getKey();
Optional<SysOperationLogTrackEnum> operationLogTrackEnum = childNodes.stream()
.filter(r -> r.getColumnName().equals(fieldName))
.findFirst();
if (operationLogTrackEnum.isPresent()) {
SysOperationLogTrackEnum sysOperationLogTrackEnum = operationLogTrackEnum.get();
JsonNode newValue = entry.getValue();
JsonNode oldValue = oldNode.get(fieldName);
if ((newValue == null || newValue.isNull()) && (oldValue != null && !oldValue.isNull())) {
OperationDetails operationDetail = sysOperationLogTrackEnum.replaceValues(
fieldName, handleJsonNode(oldValue), null
);
operationDetails.add(operationDetail);
} else if (oldValue == null || oldValue.isNull() && (newValue != null && !newValue.isNull())) {
OperationDetails operationDetail = sysOperationLogTrackEnum.replaceValues(
fieldName, null, handleJsonNode(newValue)
);
operationDetails.add(operationDetail);
} else if (oldValue.equals(newValue)) {
} else if (!sysOperationLogTrackEnum.getChildNodes().isEmpty()) {
sysOperationLogTrackEnum.compareJsonNodes(oldValue, newValue, operationDetails);
} else {
OperationDetails operationDetail = sysOperationLogTrackEnum.replaceValues(
fieldName, handleJsonNode(oldValue), handleJsonNode(newValue)
);
operationDetails.add(operationDetail);
}
}
}
}
存在的疑問
1.不可避免的需要數(shù)據(jù)對(duì)比寿桨,這種方式是否可行
2.誰來定義哪些字段需要對(duì)比
3.需要默認(rèn)展示方式如何展示钧唐,使用參數(shù)占位符如何展示
待優(yōu)化
刪除原始數(shù)據(jù)的存儲(chǔ)
異步線程池進(jìn)行存儲(chǔ)
參數(shù)占位符入?yún)⒄故?br>
空間換時(shí)間把子節(jié)點(diǎn)數(shù)據(jù)做成hashMap存儲(chǔ)減少時(shí)間復(fù)雜度
可以添加一個(gè)操作對(duì)象字段
可以把展示的方式改成一句話
展示時(shí)可以進(jìn)行對(duì)比標(biāo)記新增或刪除的內(nèi)容
假設(shè)
在只有兩層遞歸結(jié)構(gòu)的情況下佣渴,如果第一層包含數(shù)組,且每層大約有 10 個(gè)字段君躺,我們可以更具體地計(jì)算時(shí)間復(fù)雜度竿滨。
- 第一層有一個(gè)數(shù)組魁巩,數(shù)組長(zhǎng)度為
n
。 - 每個(gè)數(shù)組元素是一個(gè) JSON 對(duì)象辽旋,包含大約 10 個(gè)字段。
- 第二層遞歸處理這些 JSON 對(duì)象中的字段檐迟。
分析
1. 第一層數(shù)組處理
- 數(shù)組長(zhǎng)度為
n
补胚。 - 對(duì)數(shù)組中的每個(gè)元素,調(diào)用
compareJsonNodes
處理其內(nèi)部的 JSON 對(duì)象追迟。由于數(shù)組長(zhǎng)度為n
溶其,這一層的時(shí)間復(fù)雜度為O(n)
。
2. 第二層字段處理
- 假設(shè)每個(gè) JSON 對(duì)象包含
k
個(gè)字段(在你的例子中k ≈ 10
)敦间。 - 處理每個(gè)字段時(shí)瓶逃,可能需要對(duì)
childNodes.stream().filter(...).findFirst()
進(jìn)行線性搜索。假設(shè)childNodes
的大小為m
每瞒,則對(duì)每個(gè)字段的處理時(shí)間為O(m)
金闽。 - 第二層遞歸的復(fù)雜度為
O(k * m)
。由于k ≈ 10
剿骨,可以視為常數(shù)代芜,復(fù)雜度為O(m)
。
綜合計(jì)算
- 第一層的時(shí)間復(fù)雜度是
O(n)
浓利。 - 每個(gè)數(shù)組元素在第二層的時(shí)間復(fù)雜度為
O(m)
挤庇,由于有n
個(gè)元素,總體時(shí)間復(fù)雜度為O(n * m)
贷掖。
總時(shí)間復(fù)雜度
在這種情況下嫡秕,代碼的總時(shí)間復(fù)雜度為 O(n * m)
,其中:
-
n
是第一層數(shù)組的長(zhǎng)度苹威。 -
m
是childNodes
的大小昆咽。
由于 k ≈ 10
,這個(gè)部分基本可以視為常數(shù),不影響整體的時(shí)間復(fù)雜度計(jì)算掷酗。
a. 測(cè)試不同 n
值的性能表現(xiàn)调违,驗(yàn)證 O(n * m)
的實(shí)際影響。
b. 考慮優(yōu)化 childNodes
搜索部分泻轰,減少 m
的影響技肩。