errors | |
---|---|
|
问题1:为什么配置视图文件总是不生效?
解答:我们系统视图分为默认视图,手动配置视图。如果是默认视图,我们是没有view.json文件的。如果是手动配置视图,那么在我们的工程项目中,建立views目录建立mode.json视图文件。menu.json菜单视图配置项目中,菜单view属性配置视图模型对应的key值。app.json文件中也一同配置访问视图地址。这个时候需要重新打包我们的工程,重新跑起来即可。
问题2:为什么linux配置日志级别不生效?
解答:logback日志文件默认读取顺序为logging.xml、application.properties、logging-spring.xml,检查项目application.properties是否指定了logback配置文件,检查logback配置文件名称是否对得上,将logback配置文件对上,重启即可。
问题3:如何排查linux中jvm加载的是哪个日志配置文件?
解答:使用arthas工具排查,通过打印类的相关命令:
1.启动arthas,监控jvm,命令:./as.sh
2.查看jvm加载的日志组件,命令:logger
3.获取classLoaderHash,命令:sc -d com.sie.iiot.apps.alarm.model.AlarmManager
4.查看类加载的logger信息,命令:ognl -c 10dba097 '@com.sie.iiot.apps.alarm.model.AlarmManager@logger'
5.查看jvm加载的logger配置文件信息,命令:ognl -c 1be6f5c3 '#map1=@org.slf4j.LoggerFactory@getLogger("root").loggerContext.objectMap, #map1.get("CONFIGURATION_WATCH_LIST")'
可以看到加载的是这个配置文件/root/java-iiot/jar/sie-iiot-server-1.0-SNAPSHOT.jar!/BOOT-INF/classes!/logback.xml
问题4: 查询性能优化
如果模型中的字段有 ER 关系。引擎自动会做懒加载,但是在查询的时候,使用懒加载可能会导致性能比较差。
以下模型作为示例
@Model
public class Staff extends BaseModel<Staff> {
@ManyToOne(displayName = "部门")
@JoinColumn
private Dept dept;
@OneToMany(displayName = "学习记录")
private List<LearningRecord> learningRecords;
@Property(displayName = "附件", dataType = DataType.FILE, multiple = true, length = 10)
private List<String> file;
public List<LearningRecord> getLearningRecords() {
return (List<LearningRecord>) get("learningRecords");
}
}
@Model
public class LearningRecord extends BaseModel<LearningRecord> {
@ManyToOne(displayName = "员工")
@JoinColumn
private Staff staff;
@Property(displayName = "内容")
private String content;
}
4.1 不要在循环中使用懒加载
错误做法
for (Staff staff : staffList) {
List<LearningRecord> learningRecords = staff.getLearningRecords();
}
如果 staffList 有 100 条数据,那么会执行 100 次查询 LearningRecord 的语句。
正确做法应该是一次性查询所有相关的 LearningRecord,然后再进行下一步处理。
Set<String> staffIds = staffList.stream()
.map(BaseModel::getId)
.collect(Collectors.toSet());
List<LearningRecord> learningRecords = new ArrayList<>();
if (CollectionUtil.isNotEmpty(staffIds)) {
learningRecords = new LearningRecord().search(Filter.in("staff", staffIds), Collections.singletonList("*"), 0, 0, null);
}
for (Staff staff : staffList) {
List<LearningRecord> records = learningRecords.stream()
.filter(r -> staff.getId().equals(r.getOrDefault("staff", "")))
.collect(Collectors.toList());
// 其他处理逻辑
}
4.2 尽量不查询类型为 File 的字段
dataType = File 的字段跟 @OneToMany 类似。如果在做表格查询、导出等功能,那么不要去查询这些字段。
错误做法
new Staff().search(null, Collections.singletonList("*"), 0, 0, null);
引擎在处理上面的查询时,会发出大量的查询语句去查询 MetaAttachment 模型。
正确的做法
new Staff().search(null, Arrays.asList("id", "dept"), 0, 0, null);
5 常用Arthas命令
1.查看耗时>200ms的方法的参数和返回值
watch com.sie.snest.engine.model.property.SelectionProperty convertToRead '{params[0],params[3],returnObj}' '#cost>200' -n 100 -x 3
2. 统计耗时
trace com.sie.snest.engine.data.access.BussModelDataAccess search 'params[0].getModel().getName()=="equip_lubrication_calibration"' -n 100 --skipJDKMethod false
trace com.sie.mbm.edo.calibration.models.Calibration periodUnitList -n 100 --skipJDKMethod false
3.查看参数
watch com.sie.mi.ioc.attribution.strategy.models.AttributionStrategy calcAttribution '{params,returnObj,throwExp}' -n 20 -x 3
watch com.sie.mi.ioc.attribution.strategy.models.AttributionStrategy calcAttribution '{params,returnObj,throwExp}' 'params[0]=="04dkj8y9h3kny"' -n 20 -x 3
4.其他示例
watch com.sie.snest.engine.api.response.ResponseHandle beforeBodyWrite '{params,returnObj,throwExp}' -n 100 --skipJDKMethod false
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.sie.snest.engine.container.EngineContainer@getBussinessAppGroupContainer().getAppDataInfoMap().keySet()'
watch com.sie.snest
trace com.sie.snest.engine.api.distributed.RpcInvocation invoke -n 5 --skipJDKMethod false
trace com.sie.snest.engine.api.distributed.RpcInvocation invoke 'ModelMeta == "mbm_mes_process_match_rule"'
stack com.sie.snest.engine.api.response.ResponseHandle beforeBodyWrite -n 20 --skipJDKMethod false
trace org.springframework.web.servlet.DispatcherServlet doDispatch -n 20 --skipJDKMethod false
watch com.sie.mi.ioc.attribution.strategy.models.AttributionStrategy calcAttribution '{params,returnObj.reportResult.candidateResult.dimList[0].dataList[0].reportData,throwExp}' 'params[0]=="04dkj8y9h3kny"' -n 20 -x 3
watch com.sie.mi.ioc.attribution.strategy.models.AttributionStrategy calcAttribution '{params,returnObj,throwExp}' 'params[0]=="04dkj8y9h3kny"' -n 20 -x 3
watch com.sie.snest.engine.api.RpcController service '{params,returnObj,throwExp}' -n 20 -x 3
watch com.sie.snest.engine.api.response.ResponseHandle beforeBodyWrite '{params,returnObj,throwExp}' -n 100 -x 3
trace com.sie.snest.engine.api.distributed.RpcInvocation invoke 'params[3]=="mbm_mes_process_match_rule"' -n 100 --skipJDKMethod false
trace com.sie.snest.engine.api.RpcController service 'params[1].getParameter("businessIndex")=="04dkj8y9h3kny"' -n 20 --skipJDKMethod false
watch com.sie.snest.engine.api.RpcController service '{params,returnObj,throwExp}' 'params[1].getParameter("businessIndex")=="04dkj8y9h3kny"' -n 100 -x 3
trace com.sie.snest.engine.api.RpcController service 'params[1].getParameter("businessIndex")=="04dkj8y9h3kny"' -n 20 --skipJDKMethod false
trace com.sie.snest.engine.api.response.ResponseHandle beforeBodyWrite -n 20 --skipJDKMethod false