ai-engineering-init 1.3.4 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/.claude/hooks/skill-forced-eval.js +2 -0
  2. package/.claude/settings.json +3 -3
  3. package/.claude/skills/add-skill/SKILL.md +79 -32
  4. package/.claude/skills/api-development/SKILL.md +83 -377
  5. package/.claude/skills/architecture-design/SKILL.md +138 -632
  6. package/.claude/skills/backend-annotations/SKILL.md +134 -506
  7. package/.claude/skills/banana-image/SKILL.md +10 -3
  8. package/.claude/skills/brainstorm/SKILL.md +103 -535
  9. package/.claude/skills/bug-detective/SKILL.md +147 -1097
  10. package/.claude/skills/bug-detective/references/error-patterns.md +242 -0
  11. package/.claude/skills/code-patterns/SKILL.md +116 -426
  12. package/.claude/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  13. package/.claude/skills/crud-development/SKILL.md +64 -304
  14. package/.claude/skills/data-permission/SKILL.md +105 -412
  15. package/.claude/skills/data-permission/references/custom-data-scope.md +90 -0
  16. package/.claude/skills/file-oss-management/SKILL.md +106 -714
  17. package/.claude/skills/file-oss-management/references/entities.md +105 -0
  18. package/.claude/skills/file-oss-management/references/service-impl.md +104 -0
  19. package/.claude/skills/leniu-api-development/SKILL.md +142 -626
  20. package/.claude/skills/leniu-api-development/references/real-examples.md +273 -0
  21. package/.claude/skills/leniu-architecture-design/SKILL.md +176 -391
  22. package/.claude/skills/leniu-backend-annotations/SKILL.md +132 -519
  23. package/.claude/skills/leniu-brainstorm/SKILL.md +132 -541
  24. package/.claude/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  25. package/.claude/skills/leniu-crud-development/SKILL.md +232 -938
  26. package/.claude/skills/leniu-crud-development/references/templates.md +597 -0
  27. package/.claude/skills/leniu-customization-location/SKILL.md +410 -0
  28. package/.claude/skills/leniu-data-permission/SKILL.md +70 -0
  29. package/.claude/skills/leniu-java-entity/SKILL.md +76 -590
  30. package/.claude/skills/leniu-java-entity/references/templates.md +237 -0
  31. package/.claude/skills/leniu-java-export/SKILL.md +94 -379
  32. package/.claude/skills/leniu-java-logging/SKILL.md +106 -709
  33. package/.claude/skills/leniu-java-logging/references/data-mask.md +46 -0
  34. package/.claude/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  35. package/.claude/skills/leniu-java-mybatis/SKILL.md +73 -446
  36. package/.claude/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  37. package/.claude/skills/leniu-report-customization/SKILL.md +111 -365
  38. package/.claude/skills/leniu-report-customization/references/table-fields.md +93 -0
  39. package/.claude/skills/leniu-report-standard-customization/SKILL.md +111 -334
  40. package/.claude/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  41. package/.claude/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  42. package/.claude/skills/leniu-security-guard/SKILL.md +133 -347
  43. package/.claude/skills/mysql-debug/SKILL.md +364 -0
  44. package/.claude/skills/openspec-apply-change/SKILL.md +10 -1
  45. package/.claude/skills/openspec-archive-change/SKILL.md +9 -1
  46. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  47. package/.claude/skills/openspec-continue-change/SKILL.md +9 -1
  48. package/.claude/skills/openspec-explore/SKILL.md +10 -1
  49. package/.claude/skills/openspec-ff-change/SKILL.md +9 -1
  50. package/.claude/skills/openspec-new-change/SKILL.md +9 -1
  51. package/.claude/skills/openspec-onboard/SKILL.md +15 -130
  52. package/.claude/skills/openspec-sync-specs/SKILL.md +9 -1
  53. package/.claude/skills/openspec-verify-change/SKILL.md +9 -1
  54. package/.claude/skills/performance-doctor/SKILL.md +110 -434
  55. package/.claude/skills/redis-cache/SKILL.md +89 -595
  56. package/.claude/skills/redis-cache/references/listeners.md +23 -0
  57. package/.claude/skills/scheduled-jobs/SKILL.md +88 -407
  58. package/.claude/skills/security-guard/SKILL.md +137 -532
  59. package/.claude/skills/security-guard/references/encrypt-config.md +103 -0
  60. package/.claude/skills/security-guard/references/sensitive-strategies.md +42 -0
  61. package/.claude/skills/sms-mail/SKILL.md +116 -574
  62. package/.claude/skills/sms-mail/references/mail-config.md +88 -0
  63. package/.claude/skills/sms-mail/references/sms-config.md +74 -0
  64. package/.claude/skills/social-login/SKILL.md +112 -514
  65. package/.claude/skills/social-login/references/provider-configs.md +118 -0
  66. package/.claude/skills/tenant-management/SKILL.md +129 -444
  67. package/.claude/skills/tenant-management/references/tenant-scenarios.md +91 -0
  68. package/.claude/skills/test-development/SKILL.md +86 -540
  69. package/.claude/skills/test-development/references/parameterized-examples.md +119 -0
  70. package/.claude/skills/utils-toolkit/SKILL.md +52 -305
  71. package/.claude/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  72. package/.claude/skills/websocket-sse/SKILL.md +105 -550
  73. package/.claude/skills/workflow-engine/SKILL.md +147 -502
  74. package/.codex/skills/add-skill/SKILL.md +79 -32
  75. package/.codex/skills/api-development/SKILL.md +172 -599
  76. package/.codex/skills/architecture-design/SKILL.md +138 -504
  77. package/.codex/skills/backend-annotations/SKILL.md +134 -496
  78. package/.codex/skills/banana-image/SKILL.md +10 -3
  79. package/.codex/skills/brainstorm/SKILL.md +103 -535
  80. package/.codex/skills/bug-detective/SKILL.md +147 -1097
  81. package/.codex/skills/bug-detective/references/error-patterns.md +242 -0
  82. package/.codex/skills/code-patterns/SKILL.md +120 -282
  83. package/.codex/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  84. package/.codex/skills/crud-development/SKILL.md +64 -292
  85. package/.codex/skills/data-permission/SKILL.md +108 -407
  86. package/.codex/skills/data-permission/references/custom-data-scope.md +90 -0
  87. package/.codex/skills/database-ops/SKILL.md +8 -154
  88. package/.codex/skills/error-handler/SKILL.md +10 -0
  89. package/.codex/skills/file-oss-management/SKILL.md +106 -714
  90. package/.codex/skills/file-oss-management/references/entities.md +105 -0
  91. package/.codex/skills/file-oss-management/references/service-impl.md +104 -0
  92. package/.codex/skills/git-workflow/SKILL.md +27 -5
  93. package/.codex/skills/leniu-api-development/SKILL.md +142 -626
  94. package/.codex/skills/leniu-api-development/references/real-examples.md +273 -0
  95. package/.codex/skills/leniu-architecture-design/SKILL.md +176 -391
  96. package/.codex/skills/leniu-backend-annotations/SKILL.md +132 -519
  97. package/.codex/skills/leniu-brainstorm/SKILL.md +132 -541
  98. package/.codex/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  99. package/.codex/skills/leniu-crud-development/SKILL.md +232 -938
  100. package/.codex/skills/leniu-crud-development/references/templates.md +597 -0
  101. package/.codex/skills/leniu-customization-location/SKILL.md +410 -0
  102. package/.codex/skills/leniu-data-permission/SKILL.md +70 -0
  103. package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
  104. package/.codex/skills/leniu-java-entity/SKILL.md +76 -590
  105. package/.codex/skills/leniu-java-entity/references/templates.md +237 -0
  106. package/.codex/skills/leniu-java-export/SKILL.md +94 -379
  107. package/.codex/skills/leniu-java-logging/SKILL.md +106 -709
  108. package/.codex/skills/leniu-java-logging/references/data-mask.md +46 -0
  109. package/.codex/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  110. package/.codex/skills/leniu-java-mybatis/SKILL.md +73 -446
  111. package/.codex/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  112. package/.codex/skills/leniu-report-customization/SKILL.md +111 -365
  113. package/.codex/skills/leniu-report-customization/references/table-fields.md +93 -0
  114. package/.codex/skills/leniu-report-standard-customization/SKILL.md +111 -334
  115. package/.codex/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  116. package/.codex/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  117. package/.codex/skills/leniu-security-guard/SKILL.md +133 -347
  118. package/.codex/skills/mysql-debug/SKILL.md +364 -0
  119. package/.codex/skills/openspec-apply-change/SKILL.md +10 -1
  120. package/.codex/skills/openspec-archive-change/SKILL.md +9 -1
  121. package/.codex/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  122. package/.codex/skills/openspec-continue-change/SKILL.md +9 -1
  123. package/.codex/skills/openspec-explore/SKILL.md +10 -1
  124. package/.codex/skills/openspec-ff-change/SKILL.md +9 -1
  125. package/.codex/skills/openspec-new-change/SKILL.md +9 -1
  126. package/.codex/skills/openspec-onboard/SKILL.md +15 -130
  127. package/.codex/skills/openspec-sync-specs/SKILL.md +9 -1
  128. package/.codex/skills/openspec-verify-change/SKILL.md +9 -1
  129. package/.codex/skills/performance-doctor/SKILL.md +110 -434
  130. package/.codex/skills/project-navigator/SKILL.md +20 -1
  131. package/.codex/skills/redis-cache/SKILL.md +93 -589
  132. package/.codex/skills/redis-cache/references/listeners.md +23 -0
  133. package/.codex/skills/scheduled-jobs/SKILL.md +88 -407
  134. package/.codex/skills/security-guard/SKILL.md +141 -527
  135. package/.codex/skills/security-guard/references/encrypt-config.md +103 -0
  136. package/.codex/skills/security-guard/references/sensitive-strategies.md +42 -0
  137. package/.codex/skills/sms-mail/SKILL.md +116 -574
  138. package/.codex/skills/sms-mail/references/mail-config.md +88 -0
  139. package/.codex/skills/sms-mail/references/sms-config.md +74 -0
  140. package/.codex/skills/social-login/SKILL.md +112 -514
  141. package/.codex/skills/social-login/references/provider-configs.md +118 -0
  142. package/.codex/skills/store-pc/SKILL.md +258 -383
  143. package/.codex/skills/tenant-management/SKILL.md +129 -444
  144. package/.codex/skills/tenant-management/references/tenant-scenarios.md +91 -0
  145. package/.codex/skills/test-development/SKILL.md +86 -540
  146. package/.codex/skills/test-development/references/parameterized-examples.md +119 -0
  147. package/.codex/skills/ui-pc/SKILL.md +350 -387
  148. package/.codex/skills/utils-toolkit/SKILL.md +52 -283
  149. package/.codex/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  150. package/.codex/skills/websocket-sse/SKILL.md +105 -550
  151. package/.codex/skills/workflow-engine/SKILL.md +147 -502
  152. package/.cursor/hooks/cursor-skill-eval.js +53 -1
  153. package/.cursor/hooks.json +3 -3
  154. package/.cursor/skills/add-skill/SKILL.md +79 -32
  155. package/.cursor/skills/api-development/SKILL.md +83 -377
  156. package/.cursor/skills/architecture-design/SKILL.md +138 -632
  157. package/.cursor/skills/backend-annotations/SKILL.md +134 -506
  158. package/.cursor/skills/banana-image/SKILL.md +10 -3
  159. package/.cursor/skills/brainstorm/SKILL.md +103 -535
  160. package/.cursor/skills/bug-detective/SKILL.md +147 -1097
  161. package/.cursor/skills/bug-detective/references/error-patterns.md +242 -0
  162. package/.cursor/skills/code-patterns/SKILL.md +116 -426
  163. package/.cursor/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  164. package/.cursor/skills/crud-development/SKILL.md +64 -304
  165. package/.cursor/skills/data-permission/SKILL.md +105 -412
  166. package/.cursor/skills/data-permission/references/custom-data-scope.md +90 -0
  167. package/.cursor/skills/file-oss-management/SKILL.md +106 -714
  168. package/.cursor/skills/file-oss-management/references/entities.md +105 -0
  169. package/.cursor/skills/file-oss-management/references/service-impl.md +104 -0
  170. package/.cursor/skills/git-workflow/SKILL.md +27 -5
  171. package/.cursor/skills/leniu-api-development/SKILL.md +142 -626
  172. package/.cursor/skills/leniu-api-development/references/real-examples.md +273 -0
  173. package/.cursor/skills/leniu-architecture-design/SKILL.md +176 -391
  174. package/.cursor/skills/leniu-backend-annotations/SKILL.md +132 -519
  175. package/.cursor/skills/leniu-brainstorm/SKILL.md +132 -541
  176. package/.cursor/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  177. package/.cursor/skills/leniu-crud-development/SKILL.md +232 -938
  178. package/.cursor/skills/leniu-crud-development/references/templates.md +597 -0
  179. package/.cursor/skills/leniu-customization-location/SKILL.md +410 -0
  180. package/.cursor/skills/leniu-data-permission/SKILL.md +70 -0
  181. package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
  182. package/.cursor/skills/leniu-java-entity/SKILL.md +76 -590
  183. package/.cursor/skills/leniu-java-entity/references/templates.md +237 -0
  184. package/.cursor/skills/leniu-java-export/SKILL.md +94 -379
  185. package/.cursor/skills/leniu-java-logging/SKILL.md +106 -709
  186. package/.cursor/skills/leniu-java-logging/references/data-mask.md +46 -0
  187. package/.cursor/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  188. package/.cursor/skills/leniu-java-mybatis/SKILL.md +73 -446
  189. package/.cursor/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  190. package/.cursor/skills/leniu-report-customization/SKILL.md +111 -365
  191. package/.cursor/skills/leniu-report-customization/references/table-fields.md +93 -0
  192. package/.cursor/skills/leniu-report-standard-customization/SKILL.md +111 -334
  193. package/.cursor/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  194. package/.cursor/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  195. package/.cursor/skills/leniu-security-guard/SKILL.md +133 -347
  196. package/.cursor/skills/mysql-debug/SKILL.md +364 -0
  197. package/.cursor/skills/openspec-apply-change/SKILL.md +10 -1
  198. package/.cursor/skills/openspec-archive-change/SKILL.md +9 -1
  199. package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  200. package/.cursor/skills/openspec-continue-change/SKILL.md +9 -1
  201. package/.cursor/skills/openspec-explore/SKILL.md +10 -1
  202. package/.cursor/skills/openspec-ff-change/SKILL.md +9 -1
  203. package/.cursor/skills/openspec-new-change/SKILL.md +9 -1
  204. package/.cursor/skills/openspec-onboard/SKILL.md +15 -130
  205. package/.cursor/skills/openspec-sync-specs/SKILL.md +9 -1
  206. package/.cursor/skills/openspec-verify-change/SKILL.md +9 -1
  207. package/.cursor/skills/performance-doctor/SKILL.md +110 -434
  208. package/.cursor/skills/redis-cache/SKILL.md +89 -595
  209. package/.cursor/skills/redis-cache/references/listeners.md +23 -0
  210. package/.cursor/skills/scheduled-jobs/SKILL.md +88 -407
  211. package/.cursor/skills/security-guard/SKILL.md +137 -532
  212. package/.cursor/skills/security-guard/references/encrypt-config.md +103 -0
  213. package/.cursor/skills/security-guard/references/sensitive-strategies.md +42 -0
  214. package/.cursor/skills/sms-mail/SKILL.md +116 -574
  215. package/.cursor/skills/sms-mail/references/mail-config.md +88 -0
  216. package/.cursor/skills/sms-mail/references/sms-config.md +74 -0
  217. package/.cursor/skills/social-login/SKILL.md +112 -514
  218. package/.cursor/skills/social-login/references/provider-configs.md +118 -0
  219. package/.cursor/skills/tenant-management/SKILL.md +129 -444
  220. package/.cursor/skills/tenant-management/references/tenant-scenarios.md +91 -0
  221. package/.cursor/skills/test-development/SKILL.md +86 -540
  222. package/.cursor/skills/test-development/references/parameterized-examples.md +119 -0
  223. package/.cursor/skills/utils-toolkit/SKILL.md +52 -305
  224. package/.cursor/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  225. package/.cursor/skills/websocket-sse/SKILL.md +105 -550
  226. package/.cursor/skills/workflow-engine/SKILL.md +147 -502
  227. package/package.json +1 -1
@@ -19,331 +19,158 @@ description: |
19
19
 
20
20
  # 后端性能优化指南
21
21
 
22
- > ⚠️ **本项目规范**:本文档基于项目实际代码编写,所有 API 和类名均已验证。标记 `🔴 本项目规范` 的部分必须严格遵守。
23
-
24
- ## 目录
25
-
26
- - [性能问题诊断流程](#性能问题诊断流程)
27
- - [MyBatis-Plus 查询优化](#1-mybatis-plus-查询优化)
28
- - [SQL 优化](#2-sql-优化)
29
- - [缓存优化](#3-缓存优化)
30
- - [多租户优化](#4-多租户优化)
31
- - [批量操作优化](#5-批量操作优化)
32
- - [接口优化](#6-接口优化)
33
- - [性能日志分析](#7-性能日志分析)
34
- - [性能指标与监控工具](#8-性能指标与监控工具)
35
- - [常见性能问题速查](#常见性能问题速查)
36
-
37
- ---
38
-
39
- ## 性能问题诊断流程
22
+ ## 诊断流程
40
23
 
41
24
  ```
42
- 1. 定位问题
43
- ├─ 接口层面?→ 检查响应时间、调用链路
44
- ├─ SQL 层面?→ 检查慢查询、执行计划
45
- └─ 缓存层面?→ 检查命中率、过期策略
46
-
47
- 2. 分析原因
48
- ├─ 使用工具测量(p6spy/Arthas/日志分析)
49
- └─ 找出瓶颈点
25
+ 1. 定位 -> 接口层面(响应时间) / SQL层面(慢查询) / 缓存层面(命中率)
26
+ 2. 分析 -> p6spy SQL 日志 / Arthas JVM 诊断 / 日志分析
27
+ 3. 优化 -> 索引 / 缓存 / 批量处理
28
+ 4. 验证 -> 对比优化前后指标
29
+ ```
50
30
 
51
- 3. 实施优化
52
- └─ 针对性优化(索引/缓存/批量处理)
31
+ ### 性能指标
53
32
 
54
- 4. 验证效果
55
- └─ 对比优化前后(响应时间/SQL 耗时)
56
- ```
33
+ | 指标 | 良好 | 需优化 | 工具 |
34
+ |------|------|--------|------|
35
+ | 接口响应 | < 200ms | > 500ms | p6spy/SkyWalking |
36
+ | 数据库查询 | < 50ms | > 200ms | p6spy SQL 日志 |
37
+ | 内存使用 | < 70% | > 85% | Arthas/JVM 监控 |
57
38
 
58
39
  ---
59
40
 
60
41
  ## 1. MyBatis-Plus 查询优化
61
42
 
62
- > **实际代码位置**:`ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java:62-73`
43
+ > 源码:`ruoyi-modules/ruoyi-demo/.../TestDemoServiceImpl.java:62-73`
63
44
 
64
- 本项目使用 **MyBatis-Plus 原生的 LambdaQueryWrapper 和 LambdaUpdateWrapper**,没有自定义封装类。
65
-
66
- ### 🔴 查询构建规范(本项目规范)
45
+ ### 查询构建规范
67
46
 
68
47
  ```java
69
48
  import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
70
49
  import com.baomidou.mybatisplus.core.toolkit.Wrappers;
71
50
 
72
- // ✅ 正确:本项目标准写法
73
51
  private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
74
52
  Map<String, Object> params = bo.getParams();
75
53
  LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
76
-
77
- // 条件判断+查询条件
78
54
  lqw.eq(bo.getDeptId() != null, TestDemo::getDeptId, bo.getDeptId());
79
- lqw.eq(bo.getUserId() != null, TestDemo::getUserId, bo.getUserId());
80
55
  lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
81
56
  lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
82
57
  TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
83
-
84
58
  return lqw;
85
59
  }
86
-
87
- // 使用
88
- @Override
89
- public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) {
90
- LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
91
- Page<TestDemoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
92
- return TableDataInfo.build(result);
93
- }
94
60
  ```
95
61
 
96
- ### 🔴 更新构建规范(本项目规范)
62
+ ### 更新构建规范
97
63
 
98
- > **实际代码位置**:`ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java:383-404`
64
+ > 源码:`ruoyi-modules/ruoyi-system/.../SysUserServiceImpl.java:383-404`
99
65
 
100
66
  ```java
101
67
  import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
102
68
 
103
- // ✅ 正确:使用 LambdaUpdateWrapper
104
- @Override
105
- public int updateUserStatus(Long userId, String status) {
106
- return baseMapper.update(null,
107
- new LambdaUpdateWrapper<SysUser>()
108
- .set(SysUser::getStatus, status)
109
- .eq(SysUser::getUserId, userId));
110
- }
111
-
112
- // 正确:带条件的更新(只有非null值才设置)
113
- @Override
114
- public int updateUserProfile(SysUserBo user) {
115
- return baseMapper.update(null,
116
- new LambdaUpdateWrapper<SysUser>()
117
- .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName())
118
- .set(SysUser::getPhonenumber, user.getPhonenumber())
119
- .set(SysUser::getEmail, user.getEmail())
120
- .set(SysUser::getSex, user.getSex())
121
- .eq(SysUser::getUserId, user.getUserId()));
122
- }
69
+ // 精确更新
70
+ baseMapper.update(null,
71
+ new LambdaUpdateWrapper<SysUser>()
72
+ .set(SysUser::getStatus, status)
73
+ .eq(SysUser::getUserId, userId));
74
+
75
+ // 条件更新(非null才设置)
76
+ baseMapper.update(null,
77
+ new LambdaUpdateWrapper<SysUser>()
78
+ .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName())
79
+ .set(SysUser::getPhonenumber, user.getPhonenumber())
80
+ .eq(SysUser::getUserId, user.getUserId()));
123
81
  ```
124
82
 
125
- ### 智能条件的性能优势
126
-
127
- MyBatis-Plus 的条件构造器支持条件判断,自动忽略不满足的条件:
128
-
129
- ```java
130
- // ❌ 传统写法(每个条件都要判断,代码冗长)
131
- LambdaQueryWrapper<Xxx> wrapper = new LambdaQueryWrapper<>();
132
- if (bo.getId() != null) {
133
- wrapper.eq(Xxx::getId, bo.getId());
134
- }
135
- if (StringUtils.isNotBlank(bo.getName())) {
136
- wrapper.like(Xxx::getName, bo.getName());
137
- }
138
-
139
- // ✅ MyBatis-Plus 条件构造(自动处理 null 和空字符串)
140
- LambdaQueryWrapper<Xxx> lqw = Wrappers.lambdaQuery();
141
- lqw.eq(bo.getId() != null, Xxx::getId, bo.getId()); // null 自动跳过
142
- lqw.like(StringUtils.isNotBlank(bo.getName()), Xxx::getName, bo.getName()); // 空字符串自动跳过
143
- ```
144
-
145
- ### 批量更新优化
83
+ ### 批量更新
146
84
 
147
85
  ```java
148
- // ✅ 推荐:使用 Db 工具类批量更新
149
86
  import com.baomidou.mybatisplus.extension.toolkit.Db;
150
87
 
151
- public void batchUpdateStatus(List<Long> ids, String status) {
152
- List<Xxx> list = ids.stream()
153
- .map(id -> {
154
- Xxx entity = new Xxx();
155
- entity.setId(id);
156
- entity.setStatus(status);
157
- return entity;
158
- })
159
- .toList();
160
- Db.updateBatchById(list);
161
- }
88
+ // 推荐:Db 工具类批量更新
89
+ Db.updateBatchById(entityList);
162
90
 
163
- // 避免:循环单个更新(N次数据库访问)
164
- for (Long id : ids) {
165
- baseMapper.update(null,
166
- new LambdaUpdateWrapper<Xxx>()
167
- .set(Xxx::getStatus, status)
168
- .eq(Xxx::getId, id));
169
- }
91
+ // 避免:循环单个更新(N次数据库访问)
170
92
  ```
171
93
 
172
- ---
173
-
174
- ## 2. SQL 优化
175
-
176
- ### 慢查询分析
177
-
178
- ```sql
179
- -- 开启慢查询日志(MySQL 层面)
180
- SET GLOBAL slow_query_log = 'ON';
181
- SET GLOBAL long_query_time = 1; -- 超过1秒记录
182
-
183
- -- 查看慢查询配置
184
- SHOW VARIABLES LIKE '%slow_query%';
185
-
186
- -- 本项目使用 p6spy 进行 SQL 监控(非 Druid)
187
- -- 开发环境默认开启:spring.datasource.dynamic.p6spy: true
188
- -- 生产环境默认关闭:spring.datasource.dynamic.p6spy: false
189
- -- SQL 日志输出在 ./logs/console.log 中,格式包含 Consume Time
190
- ```
191
-
192
- ### 执行计划分析
193
-
194
- ```sql
195
- -- 使用 EXPLAIN 分析
196
- EXPLAIN SELECT * FROM sys_user WHERE dept_id = 100;
197
-
198
- -- 关注字段
199
- -- type: ALL(全表扫描) < index < range < ref < const
200
- -- rows: 扫描行数,越少越好
201
- -- Extra: Using filesort(需优化)、Using temporary(需优化)
202
- ```
203
-
204
- ### 索引优化
205
-
206
- ```sql
207
- -- ✅ 好的索引设计
208
- CREATE INDEX idx_dept_status ON sys_user(dept_id, status);
209
-
210
- -- 索引使用原则
211
- -- 1. 最左前缀原则
212
- -- 2. 避免在索引列上使用函数
213
- -- 3. 避免 != 和 NOT IN
214
- -- 4. 注意索引选择性
215
- ```
216
-
217
- ### N+1 查询优化
94
+ ### N+1 查询修复
218
95
 
219
96
  ```java
220
- // ❌ 不好:N+1 查询
97
+ // 错误:循环查询
221
98
  for (Order order : orders) {
222
- User user = userMapper.selectById(order.getUserId()); // 每次循环都查询
99
+ User user = userMapper.selectById(order.getUserId());
223
100
  }
224
101
 
225
- // 好的:批量查询 + Map 映射
226
- List<Long> userIds = orders.stream()
227
- .map(Order::getUserId)
228
- .distinct()
229
- .toList();
102
+ // 正确:批量查询 + Map 映射
103
+ List<Long> userIds = orders.stream().map(Order::getUserId).distinct().toList();
230
104
  Map<Long, User> userMap = userMapper.selectBatchIds(userIds).stream()
231
105
  .collect(Collectors.toMap(User::getUserId, Function.identity()));
232
-
233
106
  for (Order order : orders) {
234
- User user = userMap.get(order.getUserId()); // O(1) 查找
107
+ User user = userMap.get(order.getUserId());
235
108
  }
236
109
  ```
237
110
 
238
111
  ---
239
112
 
240
- ## 3. 缓存优化
241
-
242
- > **实际代码位置**:`ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java`
113
+ ## 2. 缓存优化
243
114
 
244
- 本项目封装了 `RedisUtils`,基于 Redisson 实现。
115
+ > 源码:`ruoyi-common/ruoyi-common-redis/.../RedisUtils.java`
245
116
 
246
- ### 基础缓存操作
117
+ ### RedisUtils 操作
247
118
 
248
119
  ```java
249
120
  import org.dromara.common.redis.utils.RedisUtils;
250
- import java.time.Duration;
251
121
 
252
- // 设置缓存(带过期时间)
253
122
  RedisUtils.setCacheObject("user:" + id, userVo, Duration.ofMinutes(30));
254
-
255
- // 获取缓存
256
123
  UserVo cached = RedisUtils.getCacheObject("user:" + id);
257
-
258
- // 删除缓存
259
124
  RedisUtils.deleteObject("user:" + id);
260
-
261
- // 检查是否存在
262
125
  boolean exists = RedisUtils.isExistsObject("user:" + id);
263
-
264
- // 设置过期时间
265
- RedisUtils.expire("user:" + id, Duration.ofHours(1));
266
126
  ```
267
127
 
268
- ### Spring Cache 注解(推荐)
128
+ ### Spring Cache 注解
269
129
 
270
130
  ```java
271
- // 使用 Spring Cache 注解(更简洁)
272
131
  @Cacheable(value = "user", key = "#id")
273
- public UserVo getById(Long id) {
274
- return MapstructUtils.convert(baseMapper.selectById(id), UserVo.class);
275
- }
132
+ public UserVo getById(Long id) { ... }
276
133
 
277
134
  @CacheEvict(value = "user", key = "#bo.id")
278
- public int update(UserBo bo) {
279
- return baseMapper.updateById(MapstructUtils.convert(bo, User.class));
280
- }
281
-
282
- // 缓存穿透防护(缓存 null 值)
283
- @Cacheable(value = "user", key = "#id", unless = "#result == null")
284
- public UserVo getById(Long id) {
285
- // ...
286
- }
135
+ public int update(UserBo bo) { ... }
287
136
  ```
288
137
 
289
- > ⚠️ **重要警告**:`@Cacheable` 方法**禁止返回不可变集合**(`List.of()`、`Set.of()`、`Map.of()`),会导致 Redis 反序列化失败!必须使用可变集合:
290
- > ```java
291
- > // ❌ 错误
292
- > return List.of("1", "2");
293
- > // ✅ 正确
294
- > return new ArrayList<>(List.of("1", "2"));
295
- > ```
138
+ > **@Cacheable 禁止返回不可变集合**(`List.of()`、`Set.of()`),Redis 反序列化会失败。必须用 `new ArrayList<>(List.of(...))`。
296
139
 
297
140
  ### 分布式锁(Lock4j)
298
141
 
299
- > **实际代码位置**:`ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java:47-67`
300
-
301
- 本项目使用 **Lock4j + Redisson** 实现分布式锁。
142
+ > 源码:`ruoyi-modules/ruoyi-demo/.../RedisLockController.java:47-67`
302
143
 
303
144
  ```java
304
- import com.baomidou.lock.LockInfo;
305
- import com.baomidou.lock.LockTemplate;
306
145
  import com.baomidou.lock.annotation.Lock4j;
146
+ import com.baomidou.lock.LockTemplate;
147
+ import com.baomidou.lock.LockInfo;
307
148
  import com.baomidou.lock.executor.RedissonLockExecutor;
308
149
 
309
- // 方式1:注解方式(推荐)
150
+ // 注解方式(推荐)
310
151
  @Lock4j(keys = {"#key"}, expire = 60000, acquireTimeout = 3000)
311
- public void doSomething(String key) {
312
- // 业务逻辑
313
- }
314
-
315
- // 方式2:编程方式
316
- @Autowired
317
- private LockTemplate lockTemplate;
152
+ public void doSomething(String key) { ... }
318
153
 
319
- public void doSomething(String key) {
320
- final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
321
- if (null == lockInfo) {
322
- throw new ServiceException("业务处理中,请稍后再试");
323
- }
324
- try {
325
- // 业务逻辑
326
- } finally {
327
- lockTemplate.releaseLock(lockInfo);
328
- }
154
+ // 编程方式
155
+ LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
156
+ if (null == lockInfo) {
157
+ throw new ServiceException("业务处理中,请稍后再试");
158
+ }
159
+ try {
160
+ // 业务逻辑
161
+ } finally {
162
+ lockTemplate.releaseLock(lockInfo);
329
163
  }
330
164
  ```
331
165
 
332
- ### 限流控制
166
+ ### 限流
333
167
 
334
168
  ```java
335
169
  import org.redisson.api.RateType;
336
170
 
337
- // 限流:每分钟最多 100 次请求
338
- long remaining = RedisUtils.rateLimiter(
339
- "api:rate:" + userId,
340
- RateType.OVERALL, // 全局限流
341
- 100, // 允许的请求数
342
- 60 // 时间窗口(秒)
343
- );
344
-
171
+ long remaining = RedisUtils.rateLimiter("api:rate:" + userId, RateType.OVERALL, 100, 60);
345
172
  if (remaining < 0) {
346
- throw new ServiceException("请求过于频繁,请稍后再试");
173
+ throw new ServiceException("请求过于频繁");
347
174
  }
348
175
  ```
349
176
 
@@ -353,49 +180,38 @@ if (remaining < 0) {
353
180
  import com.github.benmanes.caffeine.cache.Cache;
354
181
  import com.github.benmanes.caffeine.cache.Caffeine;
355
182
 
356
- // 对于热点数据,可以使用本地缓存减少 Redis 访问
357
183
  private final Cache<Long, UserVo> localCache = Caffeine.newBuilder()
358
- .maximumSize(1000) // 最大缓存数量
359
- .expireAfterWrite(5, TimeUnit.MINUTES) // 写入后5分钟过期
184
+ .maximumSize(1000)
185
+ .expireAfterWrite(5, TimeUnit.MINUTES)
360
186
  .build();
361
187
 
362
- public UserVo getUserWithLocalCache(Long id) {
188
+ public UserVo getUser(Long id) {
363
189
  return localCache.get(id, key -> {
364
- // 本地缓存未命中,从 Redis 或数据库获取
365
190
  UserVo cached = RedisUtils.getCacheObject("user:" + id);
366
- if (cached != null) {
367
- return cached;
368
- }
369
- return MapstructUtils.convert(baseMapper.selectById(id), UserVo.class);
191
+ return cached != null ? cached : baseMapper.selectVoById(id);
370
192
  });
371
193
  }
372
194
  ```
373
195
 
374
196
  ---
375
197
 
376
- ## 4. 多租户优化
377
-
378
- 本项目使用 `TenantEntity` 实现多租户,需要注意索引设计。
198
+ ## 3. 多租户优化
379
199
 
380
200
  ```sql
381
- -- ✅ 必须为 tenant_id 建立索引
201
+ -- tenant_id 必须建索引
382
202
  CREATE INDEX idx_tenant_id ON xxx_table(tenant_id);
383
203
 
384
- -- 复合索引:租户 + 常用查询条件
204
+ -- 复合索引第一列放 tenant_id(多租户自动添加 tenant_id 条件)
385
205
  CREATE INDEX idx_tenant_status ON xxx_table(tenant_id, status);
386
206
  CREATE INDEX idx_tenant_create_time ON xxx_table(tenant_id, create_time);
387
- CREATE INDEX idx_tenant_user ON xxx_table(tenant_id, create_by);
388
-
389
- -- ⚠️ 注意:多租户查询会自动添加 tenant_id 条件
390
- -- 确保复合索引的第一列是 tenant_id
391
207
  ```
392
208
 
393
209
  ---
394
210
 
395
- ## 5. 批量操作优化
211
+ ## 4. 批量操作优化
396
212
 
397
213
  ```java
398
- // ✅ 推荐:分批插入(每批500条)
214
+ // 推荐:分批处理(每批500条)
399
215
  public void batchInsert(List<Xxx> list) {
400
216
  int batchSize = 500;
401
217
  for (int i = 0; i < list.size(); i += batchSize) {
@@ -404,18 +220,14 @@ public void batchInsert(List<Xxx> list) {
404
220
  }
405
221
  }
406
222
 
407
- // ❌ 避免:一次性插入大量数据
408
- baseMapper.insertBatch(hugeList); // 可能超时或内存溢出
409
-
410
- // ✅ 批量更新优化
223
+ // 批量更新同理
411
224
  @Transactional(rollbackFor = Exception.class)
412
225
  public void batchUpdate(List<XxxBo> list) {
413
226
  int batchSize = 500;
414
227
  for (int i = 0; i < list.size(); i += batchSize) {
415
228
  int end = Math.min(i + batchSize, list.size());
416
229
  List<Xxx> batch = list.subList(i, end).stream()
417
- .map(bo -> MapstructUtils.convert(bo, Xxx.class))
418
- .toList();
230
+ .map(bo -> MapstructUtils.convert(bo, Xxx.class)).toList();
419
231
  Db.updateBatchById(batch);
420
232
  }
421
233
  }
@@ -423,205 +235,69 @@ public void batchUpdate(List<XxxBo> list) {
423
235
 
424
236
  ---
425
237
 
426
- ## 6. 接口优化
427
-
428
- ```java
429
- // ❌ 不好:返回所有字段
430
- public List<Order> listOrders() {
431
- return baseMapper.selectList(null);
432
- }
433
-
434
- // ✅ 好的:只返回需要的字段(使用 VO)
435
- public List<OrderSimpleVo> listOrders() {
436
- return baseMapper.selectList(null).stream()
437
- .map(o -> MapstructUtils.convert(o, OrderSimpleVo.class))
438
- .toList();
439
- }
440
-
441
- // ✅ 好的:分页查询(本项目标准写法)
442
- public TableDataInfo<OrderVo> pageOrders(OrderBo bo, PageQuery pageQuery) {
443
- LambdaQueryWrapper<Order> lqw = buildQueryWrapper(bo);
444
- Page<OrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
445
- return TableDataInfo.build(result);
446
- }
447
- ```
448
-
449
- ---
450
-
451
- ## 7. 性能日志分析
452
-
453
- > **实际代码位置**:`ruoyi-admin/src/main/resources/logback-plus.xml:52-72`
454
-
455
- ### 日志文件位置
456
-
457
- | 环境 | 日志文件 | 说明 |
458
- |------|---------|------|
459
- | **开发环境** | `./logs/console.log` | 每次启动清空,包含所有日志和 SQL 日志 |
460
- | 生产环境 | `./logs/sys-*.log` | 分级别按天滚动,保留60天 |
238
+ ## 5. 性能日志分析
461
239
 
462
- > ⚠️ **AI 应优先分析开发环境日志**(`./logs/console.log`),因为:
463
- > - 只包含当前启动的日志,范围小,易分析
464
- > - 包含完整的 SQL 执行时间和性能数据
465
- > - 启动时自动清空,避免历史日志干扰
240
+ > 日志配置:`ruoyi-admin/src/main/resources/logback-plus.xml:52-72`
466
241
 
467
- ### AI 自动读取触发条件
242
+ ### 日志文件
468
243
 
469
- 当用户描述以下性能问题时,**AI 必须主动 Read ./logs/console.log**:
244
+ | 环境 | 文件 | 说明 |
245
+ |------|------|------|
246
+ | **开发** | `./logs/console.log` | 每次启动清空,含 SQL 日志 |
247
+ | 生产 | `./logs/sys-*.log` | 按天滚动,保留60天 |
470
248
 
471
- | 触发场景 | 关键词 | 日志分析重点 |
472
- |---------|--------|-------------|
473
- | 1. 接口响应慢 | "接口慢"、"响应时间长"、"超时" | SQL 执行时间、慢查询(>200ms)、N+1 查询 |
474
- | 2. SQL 性能问题 | "SQL慢"、"查询慢"、"数据库慢" | p6spy 日志中的 Consume Time、SQL 语句 |
475
- | 3. 内存或 CPU 高 | "内存占用"、"CPU高"、"卡顿" | OutOfMemoryError、GC 日志、线程池满 |
476
- | 4. 频繁报错 | "一直报错"、"很多错误" | ERROR 级别日志、异常堆栈、出现频率 |
477
- | 5. 启动慢 | "启动慢"、"启动时间长" | 应用启动时间、Bean 初始化耗时 |
249
+ ### SQL 监控
478
250
 
479
- ### 日志格式识别规则
251
+ 开发环境 p6spy 默认开启:`spring.datasource.dynamic.p6spy: true`
480
252
 
253
+ 日志格式:
481
254
  ```
482
- 日期时间 [请求ID] [线程] 级别 日志记录器 - 消息内容
483
-
484
- 示例1(普通日志):
485
- 2026-01-08 22:12:10 [req-123] [http-nio-8080-exec-1] INFO o.d.system.controller.SysUserController - 查询用户列表
486
-
487
- 示例2(SQL 日志 - p6spy):
488
- 2026-01-08 22:12:10 [req-123] [http-nio-8080-exec-1] INFO p6spy - Consume Time:245 ms 2026-01-08 22:12:10
255
+ 2026-01-08 22:12:10 [req-123] [...] INFO p6spy - Consume Time:245 ms
489
256
  Execute SQL:SELECT * FROM sys_user WHERE tenant_id = '000000' AND del_flag = '0'
490
257
  ```
491
258
 
492
- ### 常见性能分析场景
493
-
494
- #### 场景 1:分析慢 SQL(最常用)
259
+ ### AI 主动读日志的触发条件
495
260
 
496
- ```bash
497
- # 找出所有执行时间 > 200ms 的 SQL
498
- grep "Consume Time" ./logs/console.log | grep -E "Consume Time:[2-9][0-9]{2,}|[0-9]{4,}" | head -20
499
- ```
261
+ | 场景 | 关键词 | 分析重点 |
262
+ |------|--------|---------|
263
+ | 接口慢 | "接口慢"、"超时" | SQL 执行时间、N+1 查询 |
264
+ | SQL 慢 | "SQL慢"、"查询慢" | p6spy Consume Time |
265
+ | 内存/CPU | "内存高"、"卡顿" | OOM、GC、线程池满 |
266
+ | 频繁报错 | "一直报错" | ERROR 日志、异常频率 |
500
267
 
501
- **分析要点**:
502
- - 执行时间是否合理(一般 < 200ms)
503
- - 是否有索引缺失(WHERE 条件的字段)
504
- - 是否存在 N+1 查询(循环中重复相同 SQL)
505
- - 是否查询了不必要的字段(SELECT *)
506
-
507
- #### 场景 2:统计 SQL 执行次数(发现 N+1)
268
+ ### 分析命令
508
269
 
509
270
  ```bash
510
- # 统计每种 SQL 的执行次数
511
- grep "Execute SQL" ./logs/console.log | sed 's/WHERE.*/WHERE .../' | sort | uniq -c | sort -rn | head -20
512
- ```
513
-
514
- **N+1 特征**:
515
- - 同一个 SELECT 语句重复出现多次
516
- - 通常在循环中执行
517
- - 例如:`SELECT * FROM sys_user WHERE user_id = ?` 出现 100 次
271
+ # SQL(>200ms)
272
+ grep "Consume Time" ./logs/console.log | grep -E "Consume Time:[2-9][0-9]{2,}|[0-9]{4,}"
518
273
 
519
- #### 场景 3:查找异常和错误
274
+ # N+1 检测(同一 SQL 重复多次)
275
+ grep "Execute SQL" ./logs/console.log | sed 's/WHERE.*/WHERE .../' | sort | uniq -c | sort -rn | head -20
520
276
 
521
- ```bash
522
- # 查找所有 ERROR 日志
277
+ # 错误日志
523
278
  grep "ERROR" ./logs/console.log | tail -50
524
-
525
- # 查找超时错误
526
- grep -i "timeout\|timed out" ./logs/console.log
527
-
528
- # 查找内存溢出
529
- grep -i "OutOfMemoryError\|heap space" ./logs/console.log
530
- ```
531
-
532
- ### 完整分析示例
533
-
534
- **用户问题**:"接口调用很慢,查询用户列表需要 3 秒"
535
-
536
- **AI 分析流程**:
537
-
538
- ```bash
539
- # 1. 读取日志文件
540
- Read ./logs/console.log
541
-
542
- # 2. 搜索用户相关的 SQL
543
- grep "sys_user" ./logs/console.log | grep "Consume Time"
544
-
545
- # 3. 找到慢查询
546
- # 输出:Consume Time:2845 ms ... Execute SQL:SELECT * FROM sys_user WHERE status = '0'
547
-
548
- # 4. 分析问题
549
- # - 执行时间 2845ms(远超 200ms 阈值)
550
- # - SELECT * 查询所有字段
551
- # - WHERE status = '0' 可能缺少索引
552
-
553
- # 5. 给出优化建议
554
- ```
555
-
556
- **AI 输出**:
557
- ```
558
- 性能分析结果:
559
-
560
- 1. 慢查询定位
561
- - SQL: SELECT * FROM sys_user WHERE status = '0'
562
- - 执行时间: 2845ms(严重超标,应 < 200ms)
563
-
564
- 2. 问题原因
565
- - status 字段缺少索引,导致全表扫描
566
- - 查询所有字段(SELECT *),增加数据传输量
567
- - 未使用缓存
568
-
569
- 3. 优化方案(按优先级)
570
- ✅ 立即执行:
571
- - 添加索引: CREATE INDEX idx_status ON sys_user(status);
572
- - 只查询需要的字段
573
-
574
- ✅ 短期优化:
575
- - 添加 Redis 缓存(过期时间 5 分钟)
576
- - 使用 @Cacheable 注解
577
-
578
- 4. 预期效果
579
- - 添加索引后: 2845ms → 50ms(预计提升 98%)
580
279
  ```
581
280
 
582
281
  ---
583
282
 
584
- ## 8. 性能指标与监控工具
283
+ ## 常见问题速查
585
284
 
586
- ### 后端性能指标
285
+ | 问题 | 原因 | 方案 |
286
+ |------|------|------|
287
+ | 接口响应慢 | SQL 无索引 | 添加索引,EXPLAIN 分析 |
288
+ | 接口响应慢 | N+1 查询 | 批量查询 + Map 映射 |
289
+ | 接口响应慢 | 未缓存 | RedisUtils 或 @Cacheable |
290
+ | 分页查询慢 | 深分页 | 游标分页或限制页码 |
291
+ | 批量操作超时 | 数据量太大 | 分批500条处理 |
292
+ | 多租户查询慢 | tenant_id 无索引 | 添加 tenant_id 复合索引 |
293
+ | 内存溢出 | 大数据量一次加载 | 分批/流式处理 |
587
294
 
588
- | 指标 | 良好 | 需优化 | 测量工具 |
589
- |------|------|--------|---------|
590
- | 接口响应时间 | < 200ms | > 500ms | p6spy/SkyWalking |
591
- | 数据库查询 | < 50ms | > 200ms | p6spy SQL 日志 |
592
- | 内存使用 | < 70% | > 85% | Arthas/JVM监控 |
593
- | CPU 使用 | < 60% | > 80% | 系统监控 |
295
+ ---
594
296
 
595
- ### 后端监控工具
297
+ ## 监控工具
596
298
 
597
299
  | 工具 | 用途 | 使用方式 |
598
300
  |------|------|---------|
599
- | **p6spy** | SQL 监控、执行时间 | 开发环境自动开启(`p6spy: true`) |
301
+ | **p6spy** | SQL 监控、执行时间 | 开发环境默认开启 |
600
302
  | **Arthas** | JVM 诊断、火焰图 | `java -jar arthas-boot.jar` |
601
303
  | **SkyWalking** | 分布式链路追踪 | 需单独部署 |
602
- | **JProfiler** | 内存分析、CPU分析 | IDE 插件 |
603
-
604
- ### 日志分析命令速查
605
-
606
- | 命令 | 用途 | 示例 |
607
- |------|------|------|
608
- | `wc -l` | 统计行数 | `wc -l console.log` |
609
- | `grep` | 搜索关键词 | `grep "ERROR" console.log` |
610
- | `tail -n 100` | 查看最后 100 行 | `tail -n 100 console.log` |
611
- | `grep -A 5 -B 5` | 显示匹配行的前后 5 行 | `grep -A 5 -B 5 "ERROR" console.log` |
612
- | `sort \| uniq -c` | 统计重复次数 | `grep "Execute SQL" console.log \| sort \| uniq -c` |
613
-
614
- ---
615
-
616
- ## 常见性能问题速查
617
-
618
- | 问题现象 | 可能原因 | 解决方案 |
619
- |----------|----------|----------|
620
- | 接口响应慢 | SQL 无索引 | 添加合适索引,使用 EXPLAIN 分析 |
621
- | 接口响应慢 | N+1 查询 | 改为批量查询 + Map 映射 |
622
- | 接口响应慢 | 未使用缓存 | 使用 RedisUtils 或 @Cacheable |
623
- | 分页查询慢 | 深分页问题 | 使用游标分页或限制页码范围 |
624
- | 批量操作超时 | 一次操作太多数据 | 分批处理,每批 500 条 |
625
- | 多租户查询慢 | tenant_id 无索引 | 添加 tenant_id 复合索引 |
626
- | 频繁请求 | 无防抖/缓存 | 添加缓存或接口限流 |
627
- | 内存溢出 | 大数据量一次加载 | 分批处理、流式处理 |