@llryiop/avatar-boot-cli 1.0.0 → 1.0.2
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.
- package/docs/exam-question-generate-api.md +163 -0
- package/package.json +1 -1
- package/src/prompts.js +3 -3
- package/src/transform.js +1 -1
- package/templates/.claude/skills/avatar-boot-starter-feign/README.md +243 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/SKILL.md +47 -219
- package/templates/.claude/skills/avatar-boot-starter-feign/references//345/212/237/350/203/275/350/257/246/350/247/243.md +65 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/references//345/277/253/351/200/237/346/216/245/345/205/245/346/214/207/345/215/227.md +75 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/references//351/205/215/347/275/256/345/217/202/350/200/203.md +70 -0
- package/templates/.claude/skills/avatar-boot-starter-job/README.md +437 -0
- package/templates/.claude/skills/avatar-boot-starter-job/SKILL.md +35 -414
- package/templates/.claude/skills/avatar-boot-starter-job/references//345/270/270/350/247/201/351/227/256/351/242/230.md +55 -0
- package/templates/.claude/skills/avatar-boot-starter-job/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +124 -0
- package/templates/.claude/skills/avatar-boot-starter-job/references//347/233/221/346/216/247/346/214/207/346/240/207.md +72 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/README.md +580 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/SKILL.md +36 -560
- package/templates/.claude/skills/avatar-boot-starter-kafka/references//346/234/200/344/275/263/345/256/236/350/267/265.md +43 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/references//346/240/270/345/277/203/345/212/237/350/203/275.md +117 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/references//351/205/215/347/275/256/345/217/202/350/200/203.md +54 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/README.md +572 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/SKILL.md +40 -550
- package/templates/.claude/skills/avatar-boot-starter-mysql/references//345/256/236/344/275/223/344/270/216/345/212/237/350/203/275.md +96 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/346/225/260/346/215/256/346/272/220.md +91 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/references//351/253/230/347/272/247/347/211/271/346/200/247/344/270/216/351/205/215/347/275/256.md +59 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/README.md +901 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/SKILL.md +40 -879
- package/templates/.claude/skills/avatar-boot-starter-nacos/references//345/212/237/350/203/275/344/275/277/347/224/250.md +134 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +96 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/references//346/225/205/351/232/234/346/216/222/346/237/245.md +64 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/README.md +594 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/SKILL.md +52 -570
- package/templates/.claude/skills/avatar-boot-starter-oss/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +77 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/references//346/240/270/345/277/203/345/212/237/350/203/275.md +94 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/references//350/247/204/350/214/203/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.md +61 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/README.md +586 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/SKILL.md +42 -566
- package/templates/.claude/skills/avatar-boot-starter-redis/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +78 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/references//346/225/260/346/215/256/346/223/215/344/275/234.md +111 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/references//351/253/230/347/272/247/345/212/237/350/203/275.md +90 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/README.md +662 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/SKILL.md +48 -640
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//346/240/270/345/277/203/345/212/237/350/203/275.md +101 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//351/205/215/347/275/256/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.md +44 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//351/253/230/347/272/247/347/211/271/346/200/247.md +71 -0
- package/templates/.claude/skills/avatar-boot-starter-web/README.md +1007 -0
- package/templates/.claude/skills/avatar-boot-starter-web/SKILL.md +150 -1003
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-LogInfo/346/263/250/350/247/243.md +75 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/345/205/250/345/261/200/345/274/202/345/270/270/345/244/204/347/220/206.md +90 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/346/214/207/346/240/207/347/233/221/346/216/247.md +74 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/346/227/245/345/277/227/344/275/223/347/263/273.md +73 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/350/257/267/346/261/202/344/270/212/344/270/213/346/226/207.md +77 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/277/253/351/200/237/346/216/245/345/205/245/346/214/207/345/215/227.md +52 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//346/263/250/346/204/217/344/272/213/351/241/271.md +68 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//350/207/252/345/256/232/344/271/211/346/211/251/345/261/225/346/214/207/345/215/227.md +107 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//351/205/215/347/275/256/345/217/202/350/200/203.md +107 -0
- package/templates/.claude/skills/crud-generator/SKILL.md +133 -64
- package/templates/.claude/skills/database-design/README.md +207 -0
- package/templates/.claude/skills/database-design/SKILL.md +469 -82
- package/templates/.claude/skills/database-design/references//345/221/275/345/220/215/350/247/204/350/214/203.md +232 -0
- package/templates/.claude/skills/database-design/references//345/255/227/346/256/265/347/261/273/345/236/213/350/247/204/350/214/203.md +400 -0
- package/templates/.claude/skills/database-design/references//347/264/242/345/274/225/350/247/204/350/214/203.md +506 -0
- package/templates/README.md +65 -100
- package/templates/avatar-scaffold-api/pom.xml +0 -5
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/api/LoginFeignClient.java +2 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/exception/LoginErrorCode.java +25 -0
- package/templates/avatar-scaffold-service/pom.xml +25 -87
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/feign/DemoFeign.java +4 -1
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/UserLoginRepository.java +10 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/mapper/UserLoginMapper.java +4 -1
- package/templates/avatar-scaffold-service/src/main/resources/application-dev.yaml +3 -5
- package/templates/avatar-scaffold-service/src/main/resources/application-local.yaml +21 -21
- package/templates/pom.xml +9 -18
|
@@ -1,572 +1,62 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: avatar-boot-starter-mysql
|
|
3
|
-
description:
|
|
3
|
+
description: Avatar Boot MySQL 模块使用指南。当用户询问多数据源配置、@DS 注解、MyBatis-Plus、分页查询、数据脱敏、审计字段、慢SQL监控,或需要接入 avatar-boot-starter-mysql 时触发。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Avatar Boot
|
|
6
|
+
# Avatar Boot Starter MySQL 使用指南
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
你是 Avatar Boot MySQL 模块的使用顾问与开发助手。
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
- ✅ **MyBatis Plus 集成** - 基于 mybatis-plus-spring-boot3-starter 3.5.15,提供增强 CRUD 能力
|
|
12
|
-
- ✅ **SQL 监控** - Druid 内置 SQL 监控面板,实时查看慢 SQL 和连接池状态
|
|
13
|
-
- ✅ **自动分页** - 内置分页插件,支持多种数据库方言
|
|
14
|
-
- ✅ **代码生成** - 支持 MyBatis Plus 代码生成器,快速生成 Entity/Mapper/Service
|
|
15
|
-
- ✅ **多数据源** - 支持多数据源配置和动态切换
|
|
10
|
+
## 交互流程(必须遵守)
|
|
16
11
|
|
|
17
|
-
|
|
12
|
+
**每次被触发时,先通过 AskUserQuestion 工具询问用户意图:**
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
问题:"您好!我是 Avatar Boot MySQL 模块助手,请问您需要哪方面的帮助?"
|
|
15
|
+
选项:
|
|
16
|
+
1. **快速接入** - 添加依赖、@EnableMySQL、配置数据源
|
|
17
|
+
2. **多数据源** - @DS 注解切换数据源、主从配置
|
|
18
|
+
3. **实体与分页** - BaseEntity 审计字段、PageRequest/PageResponse 分页
|
|
19
|
+
4. **数据脱敏** - @Sensitive 注解、脱敏类型
|
|
20
|
+
5. **高级特性** - 慢SQL监控、数据权限控制
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
**根据用户选择,用 Read 工具按下方「文档读取路由」加载对应文档,然后给出具体指导。**
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
<dependency>
|
|
25
|
-
<groupId>com.iflytek.avatar.boot</groupId>
|
|
26
|
-
<artifactId>avatar-boot-starter-mysql</artifactId>
|
|
27
|
-
</dependency>
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
> 版本由 Avatar Boot BOM 统一管理,无需指定 version。
|
|
31
|
-
|
|
32
|
-
### 2. 配置文件
|
|
33
|
-
|
|
34
|
-
在 `application.yml` 中配置数据源:
|
|
35
|
-
|
|
36
|
-
```yaml
|
|
37
|
-
spring:
|
|
38
|
-
datasource:
|
|
39
|
-
type: com.alibaba.druid.pool.DruidDataSource
|
|
40
|
-
driver-class-name: com.mysql.cj.jdbc.Driver
|
|
41
|
-
url: jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
42
|
-
username: root
|
|
43
|
-
password: your-password
|
|
44
|
-
druid:
|
|
45
|
-
# 连接池配置
|
|
46
|
-
initial-size: 5 # 初始化连接数
|
|
47
|
-
min-idle: 5 # 最小空闲连接数
|
|
48
|
-
max-active: 20 # 最大活跃连接数
|
|
49
|
-
max-wait: 60000 # 获取连接最大等待时间(毫秒)
|
|
50
|
-
# 连接检测
|
|
51
|
-
validation-query: SELECT 1
|
|
52
|
-
test-while-idle: true
|
|
53
|
-
test-on-borrow: false
|
|
54
|
-
test-on-return: false
|
|
55
|
-
time-between-eviction-runs-millis: 60000 # 检测间隔
|
|
56
|
-
min-evictable-idle-time-millis: 300000 # 最小空闲时间
|
|
57
|
-
# 监控统计
|
|
58
|
-
filters: stat,wall,slf4j # 启用统计、防火墙、日志过滤器
|
|
59
|
-
stat-view-servlet:
|
|
60
|
-
enabled: true
|
|
61
|
-
url-pattern: /druid/*
|
|
62
|
-
login-username: admin
|
|
63
|
-
login-password: admin123
|
|
64
|
-
allow: ""
|
|
65
|
-
web-stat-filter:
|
|
66
|
-
enabled: true
|
|
67
|
-
url-pattern: /*
|
|
68
|
-
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
|
|
69
|
-
filter:
|
|
70
|
-
stat:
|
|
71
|
-
slow-sql-millis: 2000 # 慢 SQL 阈值(毫秒)
|
|
72
|
-
log-slow-sql: true # 记录慢 SQL
|
|
73
|
-
merge-sql: true # 合并 SQL 统计
|
|
74
|
-
wall:
|
|
75
|
-
config:
|
|
76
|
-
multi-statement-allow: false # 禁止多语句执行
|
|
77
|
-
delete-allow: true
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### 3. MyBatis Plus 配置
|
|
81
|
-
|
|
82
|
-
```yaml
|
|
83
|
-
mybatis-plus:
|
|
84
|
-
mapper-locations: classpath*:mapper/**/*.xml # Mapper XML 文件位置
|
|
85
|
-
type-aliases-package: com.example.entity # 实体类包路径
|
|
86
|
-
configuration:
|
|
87
|
-
map-underscore-to-camel-case: true # 驼峰命名映射
|
|
88
|
-
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl # SQL 日志
|
|
89
|
-
global-config:
|
|
90
|
-
db-config:
|
|
91
|
-
id-type: assign_id # 主键策略:雪花算法
|
|
92
|
-
logic-delete-field: deleted # 逻辑删除字段
|
|
93
|
-
logic-delete-value: 1 # 已删除值
|
|
94
|
-
logic-not-delete-value: 0 # 未删除值
|
|
95
|
-
table-prefix: t_ # 表名前缀(可选)
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Entity / Mapper / Service 模式
|
|
99
|
-
|
|
100
|
-
### Entity 实体类
|
|
101
|
-
|
|
102
|
-
```java
|
|
103
|
-
package com.example.entity;
|
|
104
|
-
|
|
105
|
-
import com.baomidou.mybatisplus.annotation.*;
|
|
106
|
-
import lombok.Data;
|
|
107
|
-
|
|
108
|
-
import java.io.Serial;
|
|
109
|
-
import java.io.Serializable;
|
|
110
|
-
import java.time.LocalDateTime;
|
|
111
|
-
|
|
112
|
-
@Data
|
|
113
|
-
@TableName("t_user")
|
|
114
|
-
public class User implements Serializable {
|
|
115
|
-
|
|
116
|
-
@Serial
|
|
117
|
-
private static final long serialVersionUID = 1L;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* 主键(雪花算法)
|
|
121
|
-
*/
|
|
122
|
-
@TableId(type = IdType.ASSIGN_ID)
|
|
123
|
-
private Long id;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 用户名
|
|
127
|
-
*/
|
|
128
|
-
private String username;
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* 邮箱
|
|
132
|
-
*/
|
|
133
|
-
private String email;
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* 状态:0-禁用,1-启用
|
|
137
|
-
*/
|
|
138
|
-
private Integer status;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 创建时间(自动填充)
|
|
142
|
-
*/
|
|
143
|
-
@TableField(fill = FieldFill.INSERT)
|
|
144
|
-
private LocalDateTime createTime;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* 更新时间(自动填充)
|
|
148
|
-
*/
|
|
149
|
-
@TableField(fill = FieldFill.INSERT_UPDATE)
|
|
150
|
-
private LocalDateTime updateTime;
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* 逻辑删除标识
|
|
154
|
-
*/
|
|
155
|
-
@TableLogic
|
|
156
|
-
private Integer deleted;
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Mapper 接口
|
|
161
|
-
|
|
162
|
-
```java
|
|
163
|
-
package com.example.mapper;
|
|
164
|
-
|
|
165
|
-
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
166
|
-
import com.example.entity.User;
|
|
167
|
-
import org.apache.ibatis.annotations.Mapper;
|
|
168
|
-
import org.apache.ibatis.annotations.Param;
|
|
169
|
-
import org.apache.ibatis.annotations.Select;
|
|
170
|
-
|
|
171
|
-
import java.util.List;
|
|
172
|
-
|
|
173
|
-
@Mapper
|
|
174
|
-
public interface UserMapper extends BaseMapper<User> {
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* 自定义查询(注解方式)
|
|
178
|
-
*/
|
|
179
|
-
@Select("SELECT * FROM t_user WHERE status = #{status}")
|
|
180
|
-
List<User> selectByStatus(@Param("status") Integer status);
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Service 接口与实现
|
|
185
|
-
|
|
186
|
-
```java
|
|
187
|
-
package com.example.service;
|
|
188
|
-
|
|
189
|
-
import com.baomidou.mybatisplus.extension.service.IService;
|
|
190
|
-
import com.example.entity.User;
|
|
191
|
-
|
|
192
|
-
public interface UserService extends IService<User> {
|
|
193
|
-
/**
|
|
194
|
-
* 根据用户名查询
|
|
195
|
-
*/
|
|
196
|
-
User getByUsername(String username);
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
```java
|
|
201
|
-
package com.example.service.impl;
|
|
202
|
-
|
|
203
|
-
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
204
|
-
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
205
|
-
import com.example.entity.User;
|
|
206
|
-
import com.example.mapper.UserMapper;
|
|
207
|
-
import com.example.service.UserService;
|
|
208
|
-
import org.springframework.stereotype.Service;
|
|
209
|
-
|
|
210
|
-
@Service
|
|
211
|
-
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
|
|
212
|
-
|
|
213
|
-
@Override
|
|
214
|
-
public User getByUsername(String username) {
|
|
215
|
-
return this.getOne(new LambdaQueryWrapper<User>()
|
|
216
|
-
.eq(User::getUsername, username));
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### 分页查询
|
|
222
|
-
|
|
223
|
-
```java
|
|
224
|
-
package com.example.config;
|
|
225
|
-
|
|
226
|
-
import com.baomidou.mybatisplus.annotation.DbType;
|
|
227
|
-
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
|
228
|
-
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
|
229
|
-
import org.springframework.context.annotation.Bean;
|
|
230
|
-
import org.springframework.context.annotation.Configuration;
|
|
231
|
-
|
|
232
|
-
@Configuration
|
|
233
|
-
public class MybatisPlusConfig {
|
|
234
|
-
|
|
235
|
-
@Bean
|
|
236
|
-
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
|
237
|
-
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
|
238
|
-
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
|
239
|
-
return interceptor;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
```java
|
|
245
|
-
@Service
|
|
246
|
-
@RequiredArgsConstructor
|
|
247
|
-
public class UserQueryService {
|
|
248
|
-
|
|
249
|
-
private final UserService userService;
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* 分页查询用户
|
|
253
|
-
*/
|
|
254
|
-
public IPage<User> pageQuery(int current, int size, String username) {
|
|
255
|
-
Page<User> page = new Page<>(current, size);
|
|
256
|
-
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
|
|
257
|
-
.like(StringUtils.isNotBlank(username), User::getUsername, username)
|
|
258
|
-
.eq(User::getDeleted, 0)
|
|
259
|
-
.orderByDesc(User::getCreateTime);
|
|
260
|
-
return userService.page(page, wrapper);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
## Druid 监控面板
|
|
266
|
-
|
|
267
|
-
启动应用后,访问 `http://localhost:8080/druid/` 即可查看 Druid 监控面板。
|
|
268
|
-
|
|
269
|
-
### 监控内容
|
|
270
|
-
|
|
271
|
-
| 面板 | 功能 |
|
|
272
|
-
|------|------|
|
|
273
|
-
| 数据源 | 连接池状态、活跃连接数、等待线程数 |
|
|
274
|
-
| SQL 监控 | SQL 执行次数、耗时统计、慢 SQL 列表 |
|
|
275
|
-
| SQL 防火墙 | 拦截的危险 SQL 统计 |
|
|
276
|
-
| Web 应用 | 请求 URI 统计、关联 SQL |
|
|
277
|
-
| Spring 监控 | Spring Bean 方法调用统计 |
|
|
278
|
-
|
|
279
|
-
### 安全配置
|
|
280
|
-
|
|
281
|
-
生产环境建议限制访问:
|
|
282
|
-
|
|
283
|
-
```yaml
|
|
284
|
-
spring:
|
|
285
|
-
datasource:
|
|
286
|
-
druid:
|
|
287
|
-
stat-view-servlet:
|
|
288
|
-
enabled: true
|
|
289
|
-
allow: 10.0.0.0/8 # 仅内网访问
|
|
290
|
-
deny: ""
|
|
291
|
-
login-username: ${DRUID_USERNAME}
|
|
292
|
-
login-password: ${DRUID_PASSWORD}
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
## 事务管理
|
|
296
|
-
|
|
297
|
-
### @Transactional 使用规范
|
|
298
|
-
|
|
299
|
-
```java
|
|
300
|
-
@Service
|
|
301
|
-
@RequiredArgsConstructor
|
|
302
|
-
public class OrderService {
|
|
303
|
-
|
|
304
|
-
private final OrderMapper orderMapper;
|
|
305
|
-
private final OrderItemMapper orderItemMapper;
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* 创建订单(事务)
|
|
309
|
-
* 注意:@Transactional 默认只回滚 RuntimeException
|
|
310
|
-
*/
|
|
311
|
-
@Transactional(rollbackFor = Exception.class)
|
|
312
|
-
public Long createOrder(OrderDTO dto) {
|
|
313
|
-
// 1. 创建主订单
|
|
314
|
-
Order order = new Order();
|
|
315
|
-
order.setOrderNo(generateOrderNo());
|
|
316
|
-
order.setTotalAmount(dto.getTotalAmount());
|
|
317
|
-
orderMapper.insert(order);
|
|
318
|
-
|
|
319
|
-
// 2. 创建订单明细
|
|
320
|
-
for (OrderItemDTO item : dto.getItems()) {
|
|
321
|
-
OrderItem orderItem = new OrderItem();
|
|
322
|
-
orderItem.setOrderId(order.getId());
|
|
323
|
-
orderItem.setProductId(item.getProductId());
|
|
324
|
-
orderItem.setQuantity(item.getQuantity());
|
|
325
|
-
orderItemMapper.insert(orderItem);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return order.getId();
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
### 事务最佳实践
|
|
334
|
-
|
|
335
|
-
1. **必须指定 `rollbackFor = Exception.class`**:默认只回滚 RuntimeException
|
|
336
|
-
2. **避免在事务方法中调用同类方法**:Spring AOP 代理限制,同类内部调用不生效
|
|
337
|
-
3. **事务方法必须是 public**:非 public 方法事务不生效
|
|
338
|
-
4. **控制事务粒度**:不要在大方法上加 @Transactional,只在需要事务的方法上使用
|
|
339
|
-
5. **避免事务中做耗时操作**:如 HTTP 调用、文件上传,会长时间占用数据库连接
|
|
340
|
-
|
|
341
|
-
```java
|
|
342
|
-
// 错误示例:事务中调用远程服务
|
|
343
|
-
@Transactional(rollbackFor = Exception.class)
|
|
344
|
-
public void badExample() {
|
|
345
|
-
orderMapper.insert(order);
|
|
346
|
-
// 不要在事务中做远程调用!
|
|
347
|
-
httpClient.callRemoteService(); // 如果超时,数据库连接被长时间占用
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// 正确示例:将远程调用移出事务
|
|
351
|
-
public void goodExample() {
|
|
352
|
-
createOrderInTransaction(order);
|
|
353
|
-
httpClient.callRemoteService(); // 事务外调用
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
@Transactional(rollbackFor = Exception.class)
|
|
357
|
-
public void createOrderInTransaction(Order order) {
|
|
358
|
-
orderMapper.insert(order);
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
## 多数据源配置
|
|
363
|
-
|
|
364
|
-
### 配置文件
|
|
365
|
-
|
|
366
|
-
```yaml
|
|
367
|
-
spring:
|
|
368
|
-
datasource:
|
|
369
|
-
primary:
|
|
370
|
-
type: com.alibaba.druid.pool.DruidDataSource
|
|
371
|
-
driver-class-name: com.mysql.cj.jdbc.Driver
|
|
372
|
-
url: jdbc:mysql://localhost:3306/primary_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
|
373
|
-
username: root
|
|
374
|
-
password: password1
|
|
375
|
-
druid:
|
|
376
|
-
initial-size: 5
|
|
377
|
-
max-active: 20
|
|
378
|
-
secondary:
|
|
379
|
-
type: com.alibaba.druid.pool.DruidDataSource
|
|
380
|
-
driver-class-name: com.mysql.cj.jdbc.Driver
|
|
381
|
-
url: jdbc:mysql://localhost:3306/secondary_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
|
382
|
-
username: root
|
|
383
|
-
password: password2
|
|
384
|
-
druid:
|
|
385
|
-
initial-size: 5
|
|
386
|
-
max-active: 20
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
### 数据源配置类
|
|
390
|
-
|
|
391
|
-
```java
|
|
392
|
-
package com.example.config;
|
|
393
|
-
|
|
394
|
-
import com.alibaba.druid.pool.DruidDataSource;
|
|
395
|
-
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
|
396
|
-
import org.apache.ibatis.session.SqlSessionFactory;
|
|
397
|
-
import org.mybatis.spring.annotation.MapperScan;
|
|
398
|
-
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
399
|
-
import org.springframework.context.annotation.Bean;
|
|
400
|
-
import org.springframework.context.annotation.Configuration;
|
|
401
|
-
import org.springframework.context.annotation.Primary;
|
|
402
|
-
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
403
|
-
|
|
404
|
-
import javax.sql.DataSource;
|
|
405
|
-
|
|
406
|
-
@Configuration
|
|
407
|
-
@MapperScan(basePackages = "com.example.mapper.primary",
|
|
408
|
-
sqlSessionFactoryRef = "primarySqlSessionFactory")
|
|
409
|
-
public class PrimaryDataSourceConfig {
|
|
410
|
-
|
|
411
|
-
@Primary
|
|
412
|
-
@Bean("primaryDataSource")
|
|
413
|
-
@ConfigurationProperties(prefix = "spring.datasource.primary")
|
|
414
|
-
public DataSource primaryDataSource() {
|
|
415
|
-
return new DruidDataSource();
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
@Primary
|
|
419
|
-
@Bean("primarySqlSessionFactory")
|
|
420
|
-
public SqlSessionFactory primarySqlSessionFactory(DataSource primaryDataSource) throws Exception {
|
|
421
|
-
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
|
|
422
|
-
factory.setDataSource(primaryDataSource);
|
|
423
|
-
factory.setMapperLocations(
|
|
424
|
-
new PathMatchingResourcePatternResolver()
|
|
425
|
-
.getResources("classpath:mapper/primary/**/*.xml"));
|
|
426
|
-
return factory.getObject();
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
## 自动填充配置
|
|
432
|
-
|
|
433
|
-
```java
|
|
434
|
-
package com.example.config;
|
|
435
|
-
|
|
436
|
-
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
|
437
|
-
import lombok.extern.slf4j.Slf4j;
|
|
438
|
-
import org.apache.ibatis.reflection.MetaObject;
|
|
439
|
-
import org.springframework.stereotype.Component;
|
|
440
|
-
|
|
441
|
-
import java.time.LocalDateTime;
|
|
442
|
-
|
|
443
|
-
@Slf4j
|
|
444
|
-
@Component
|
|
445
|
-
public class MyMetaObjectHandler implements MetaObjectHandler {
|
|
446
|
-
|
|
447
|
-
@Override
|
|
448
|
-
public void insertFill(MetaObject metaObject) {
|
|
449
|
-
this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
|
|
450
|
-
this.strictInsertFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
@Override
|
|
454
|
-
public void updateFill(MetaObject metaObject) {
|
|
455
|
-
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
## 慢 SQL 排查
|
|
461
|
-
|
|
462
|
-
### 1. Druid 慢 SQL 监控
|
|
463
|
-
|
|
464
|
-
通过 Druid 监控面板查看:
|
|
465
|
-
- 访问 `/druid/sql.html` 查看所有 SQL 统计
|
|
466
|
-
- 按执行时间排序,找到慢 SQL
|
|
467
|
-
- 查看 SQL 执行计划和参数
|
|
468
|
-
|
|
469
|
-
### 2. MySQL EXPLAIN 分析
|
|
470
|
-
|
|
471
|
-
```sql
|
|
472
|
-
-- 分析查询执行计划
|
|
473
|
-
EXPLAIN SELECT * FROM t_user WHERE username = 'zhangsan';
|
|
474
|
-
|
|
475
|
-
-- 关注以下字段:
|
|
476
|
-
-- type: ALL(全表扫描,需优化)、index、range、ref、const
|
|
477
|
-
-- rows: 扫描行数
|
|
478
|
-
-- Extra: Using filesort(需优化)、Using temporary(需优化)
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
### 3. 索引优化建议
|
|
482
|
-
|
|
483
|
-
- 为 WHERE 条件的字段添加索引
|
|
484
|
-
- 避免在索引列上使用函数或计算
|
|
485
|
-
- 联合索引遵循最左前缀原则
|
|
486
|
-
- 使用覆盖索引减少回表查询
|
|
487
|
-
|
|
488
|
-
## 最佳实践
|
|
489
|
-
|
|
490
|
-
### 1. 连接池配置
|
|
491
|
-
|
|
492
|
-
- **initial-size 和 min-idle 相同**:避免连接池频繁创建/销毁连接
|
|
493
|
-
- **max-active 合理设置**:建议 20-50,根据服务器配置和并发量调整
|
|
494
|
-
- **启用 test-while-idle**:定期检测空闲连接有效性
|
|
495
|
-
- **设置 max-wait**:避免无限等待连接
|
|
496
|
-
|
|
497
|
-
### 2. SQL 规范
|
|
498
|
-
|
|
499
|
-
- **禁止 SELECT ***:明确指定需要的列
|
|
500
|
-
- **分页查询必须加 LIMIT**:避免全表查询
|
|
501
|
-
- **批量操作使用 batch**:MyBatis Plus 的 `saveBatch()` 方法
|
|
502
|
-
- **大表查询走索引**:通过 EXPLAIN 验证
|
|
503
|
-
|
|
504
|
-
### 3. MyBatis Plus 使用
|
|
505
|
-
|
|
506
|
-
- **优先使用 LambdaQueryWrapper**:类型安全,重构友好
|
|
507
|
-
- **合理使用逻辑删除**:高频查询表注意索引包含 deleted 字段
|
|
508
|
-
- **Entity 实现 Serializable**:支持缓存序列化
|
|
509
|
-
- **使用自动填充**:createTime、updateTime 统一处理
|
|
510
|
-
|
|
511
|
-
## 常见问题
|
|
512
|
-
|
|
513
|
-
### 1. 连接池耗尽(Pool exhausted)
|
|
514
|
-
|
|
515
|
-
**原因**:并发量过大或连接泄漏
|
|
516
|
-
|
|
517
|
-
**解决**:
|
|
518
|
-
- 增大 `max-active` 配置
|
|
519
|
-
- 检查是否有未关闭的连接(使用 try-with-resources)
|
|
520
|
-
- 启用 Druid 的 `removeAbandoned` 配置回收泄漏连接
|
|
521
|
-
- 检查事务方法中是否有耗时操作占用连接
|
|
522
|
-
|
|
523
|
-
### 2. 连接超时(Connection timeout)
|
|
524
|
-
|
|
525
|
-
**原因**:MySQL 服务端关闭了空闲连接
|
|
526
|
-
|
|
527
|
-
**解决**:
|
|
528
|
-
- 启用 `test-while-idle: true` 检测空闲连接
|
|
529
|
-
- 设置 `time-between-eviction-runs-millis` 小于 MySQL 的 `wait_timeout`
|
|
530
|
-
- 检查 MySQL `max_connections` 配置
|
|
531
|
-
|
|
532
|
-
### 3. 慢查询导致性能问题
|
|
24
|
+
---
|
|
533
25
|
|
|
534
|
-
|
|
26
|
+
## 行为准则
|
|
535
27
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
- 添加合适的索引
|
|
540
|
-
- 优化 SQL 写法,避免全表扫描
|
|
28
|
+
1. **回答要具体**:引用具体的注解、类名、配置项
|
|
29
|
+
2. **主动提醒**:需要 `@EnableMySQL` 注解才能启用模块
|
|
30
|
+
3. **使用中文回答**
|
|
541
31
|
|
|
542
|
-
|
|
32
|
+
---
|
|
543
33
|
|
|
544
|
-
|
|
34
|
+
## 文档读取路由
|
|
545
35
|
|
|
546
|
-
|
|
547
|
-
- 检查 `global-config.db-config.logic-delete-field` 配置
|
|
548
|
-
- 确保实体类字段添加 `@TableLogic` 注解
|
|
549
|
-
- 自定义 SQL 不会自动添加逻辑删除条件,需手动处理
|
|
36
|
+
> 所有路径相对于 skill 目录 `docs/skills/avatar-boot-starter-mysql-skill/`
|
|
550
37
|
|
|
551
|
-
|
|
38
|
+
| 用户需求 | 需读取的文件 |
|
|
39
|
+
|:--|:--|
|
|
40
|
+
| 快速接入 / 多数据源 | `references/快速接入与数据源.md` |
|
|
41
|
+
| 实体与分页 / 数据脱敏 | `references/实体与功能.md` |
|
|
42
|
+
| 高级特性 / 配置说明 | `references/高级特性与配置.md` |
|
|
552
43
|
|
|
553
|
-
|
|
44
|
+
---
|
|
554
45
|
|
|
555
|
-
|
|
556
|
-
- 使用 `saveBatch()` 方法批量插入
|
|
557
|
-
- JDBC URL 添加 `rewriteBatchedStatements=true` 参数
|
|
558
|
-
- 控制每批次大小(推荐 500-1000 条)
|
|
46
|
+
## 通用参考信息
|
|
559
47
|
|
|
560
|
-
|
|
48
|
+
### 核心类速查
|
|
561
49
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
50
|
+
| 类/注解 | 包路径 | 用途 |
|
|
51
|
+
|:--|:--|:--|
|
|
52
|
+
| `@EnableMySQL` | 启动类 | 启用 MySQL 模块 |
|
|
53
|
+
| `@DS` | `com.baomidou.dynamic.datasource.annotation` | 切换数据源 |
|
|
54
|
+
| `BaseEntity` | `com.iflytek.avatar.boot.mysql.entity` | 审计字段基类 |
|
|
55
|
+
| `@Sensitive` | `com.iflytek.avatar.boot.mysql.sensitive` | 数据脱敏注解 |
|
|
56
|
+
| `PageRequest` | `com.iflytek.avatar.boot.mysql.page` | 分页请求 |
|
|
57
|
+
| `PageResponse` | `com.iflytek.avatar.boot.mysql.page` | 分页响应 |
|
|
58
|
+
| `UserContextHolder` | `com.iflytek.avatar.boot.mysql.handler` | 设置当前用户 |
|
|
567
59
|
|
|
568
|
-
|
|
60
|
+
### BaseEntity 字段
|
|
569
61
|
|
|
570
|
-
|
|
571
|
-
- [Druid 官方文档](https://github.com/alibaba/druid/wiki)
|
|
572
|
-
- [Spring Boot 数据访问](https://docs.spring.io/spring-boot/reference/data/sql.html)
|
|
62
|
+
`id`(雪花算法)、`createTime`、`updateTime`、`createBy`、`updateBy`、`deleted`
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# MySQL 实体与功能
|
|
2
|
+
|
|
3
|
+
## BaseEntity 审计字段
|
|
4
|
+
|
|
5
|
+
继承 `BaseEntity` 自动获得审计字段(创建时间、更新时间、创建人、更新人、逻辑删除):
|
|
6
|
+
|
|
7
|
+
```java
|
|
8
|
+
import com.iflytek.avatar.boot.mysql.entity.BaseEntity;
|
|
9
|
+
import com.baomidou.mybatisplus.annotation.TableName;
|
|
10
|
+
import lombok.Data;
|
|
11
|
+
import lombok.EqualsAndHashCode;
|
|
12
|
+
|
|
13
|
+
@Data
|
|
14
|
+
@EqualsAndHashCode(callSuper = true)
|
|
15
|
+
@TableName("sys_user")
|
|
16
|
+
public class User extends BaseEntity {
|
|
17
|
+
private String username;
|
|
18
|
+
private String email;
|
|
19
|
+
private Integer status;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`BaseEntity` 包含字段:`id`(雪花算法)、`createTime`、`updateTime`、`createBy`、`updateBy`、`deleted`
|
|
24
|
+
|
|
25
|
+
### 设置当前用户(用于审计字段自动填充)
|
|
26
|
+
|
|
27
|
+
```java
|
|
28
|
+
import com.iflytek.avatar.boot.mysql.handler.UserContextHolder;
|
|
29
|
+
|
|
30
|
+
// 在拦截器或过滤器中设置
|
|
31
|
+
UserContextHolder.setUserId("user123");
|
|
32
|
+
|
|
33
|
+
// 请求结束后清除
|
|
34
|
+
UserContextHolder.clear();
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 分页查询
|
|
38
|
+
|
|
39
|
+
```java
|
|
40
|
+
import com.iflytek.avatar.boot.mysql.page.PageRequest;
|
|
41
|
+
import com.iflytek.avatar.boot.mysql.page.PageResponse;
|
|
42
|
+
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
43
|
+
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
44
|
+
|
|
45
|
+
@Service
|
|
46
|
+
public class UserService {
|
|
47
|
+
|
|
48
|
+
@Autowired
|
|
49
|
+
private UserMapper userMapper;
|
|
50
|
+
|
|
51
|
+
public PageResponse<User> page(PageRequest request) {
|
|
52
|
+
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
|
53
|
+
wrapper.eq(User::getStatus, 1);
|
|
54
|
+
|
|
55
|
+
Page<User> page = new Page<>(request.getPageNum(), request.getPageSize());
|
|
56
|
+
page = userMapper.selectPage(page, wrapper);
|
|
57
|
+
|
|
58
|
+
return PageResponse.of(page.getRecords(), page.getTotal(), request);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 数据脱敏
|
|
64
|
+
|
|
65
|
+
使用 `@Sensitive` 注解标记需要脱敏的字段:
|
|
66
|
+
|
|
67
|
+
```java
|
|
68
|
+
import com.iflytek.avatar.boot.mysql.sensitive.Sensitive;
|
|
69
|
+
import com.iflytek.avatar.boot.mysql.sensitive.SensitiveType;
|
|
70
|
+
|
|
71
|
+
@Data
|
|
72
|
+
@TableName("sys_user")
|
|
73
|
+
public class User extends BaseEntity {
|
|
74
|
+
private String username;
|
|
75
|
+
|
|
76
|
+
@Sensitive(type = SensitiveType.MOBILE_PHONE) // 138****8888
|
|
77
|
+
private String phone;
|
|
78
|
+
|
|
79
|
+
@Sensitive(type = SensitiveType.ID_CARD) // 110101********1234
|
|
80
|
+
private String idCard;
|
|
81
|
+
|
|
82
|
+
@Sensitive(type = SensitiveType.EMAIL) // zh**@example.com
|
|
83
|
+
private String email;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 支持的脱敏类型
|
|
88
|
+
|
|
89
|
+
| 类型 | 说明 | 示例 |
|
|
90
|
+
|:--|:--|:--|
|
|
91
|
+
| `MOBILE_PHONE` | 手机号 | `138****8888` |
|
|
92
|
+
| `ID_CARD` | 身份证号 | 保留前6后4位 |
|
|
93
|
+
| `EMAIL` | 邮箱 | 保留前2位和@后内容 |
|
|
94
|
+
| `BANK_CARD` | 银行卡号 | 保留前6后4位 |
|
|
95
|
+
| `ADDRESS` | 地址 | 保留前6位 |
|
|
96
|
+
| `CHINESE_NAME` | 中文姓名 | 保留姓氏 |
|