
一、 中枢架构分层圭表 (数据流转)强制: 死守 Controller -> Service -> Mapper 的单向调用链。强制: 严禁 Service 轮回依赖。若 A 需调用 B,B 也需调用 A,必须将共有逻辑索取至第三个 Service 或 Manager 层。圭表: 扫数的 POJO 休养(Entity ↔ DTO ↔ VO)提议使用 MapStruct ,幸免手动 BeanUtils.copyProperties 导致的反射性能损耗及字段名对不上的 Bug。二、 实体类 (Entity) 与数据库建模强制: 中枢主键使用 Long 类型,并合作 Jackson 搞定 JS 精度丢失 问题:@TableId(type = IdType.ASSIGN_ID) #后端
@JsonSerialize(using = ToStringSerializer.class) // 防护前端丢失临了两位精度
private Long id; 圭表: 如有需要使用 乐不雅锁 机制防护数据并发阴私。数据库加多 version 字段。Entity 加多 @Version 注解。@Data
public class User extends BaseEntity {
// ... 其他字段
@Version // 要道:瑰丽为乐不雅锁字段 private Integer version; }
// 注入插件(在 Config 类中)
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor); 只支援 updateById 和 update 口头 :乐不雅锁插件唯有在通过实体对象(带 ID 和 Version)进行更新时才见效。处理失败逻辑 :当 update 复返 0(失败)时,你需要决定是报错给前端“系统勤奋”,仍是自动发起重试(重新查询 -> 修改 -> 再提交)。严禁手动改 Version :在业务代码里,你不需要实践 user.setVersion(user.getVersion + 1) ,MyBatis-Plus 插件会自动帮你完成这个手脚。圭表: 情景字段提议使用 IEnum 接口排列,幸免代码中出现 if (status == 1) 。public enum StatusEnum {
DISABLED(0, "禁用"), ACTIVE(1, "启用");
@EnumValue // 瑰丽这个字段存入数据库 private final int code;
private final String desc; }
三、 事务管制规约 (防护 10% 的隐形 Bug)强制: 严禁在 Service 里面 自调用 标注了 @Transactional 的口头(会导致 AOP 事务失效)。修正决议: 拆分到不同类,或使用 AopContext.currentProxy 。或我方注入我方// 使用延长加载,幸免启动时的轮回依赖检测问题
@Autowired
@Lazy
private UserService self; 强制: 事务口头内严禁进行 网罗 IO 操作 (如调用第三方支付接口、发邮件)。原因: 网罗延长会导致数据库贯穿永恒不开释,瞬息撑爆贯穿池。圭表: 声明式事务提议只加在 update/insert 口头上,查询口头不加事务。四、 代码编写“六不准” (硬性军规)不准在 IN 查询中传入跳动 1000 个元素 :风险: 部分数据库(如 Oracle)有 1000 个上限,且 SQL 过长导致索引失效。不准在 Mapper.xml 中使用 ${} :风险: 99% 的 SQL 注入源于此。除 ORDER BY 动态排序外,一律使用 #{} 。不准在莫得 Where 条目下实践 update/delete :治安: 必须设立 BlockAttackInnerInterceptor 插件。不准在轮回中调用 saveOrUpdate :风险: 每次判断存在齐会先实践一次 SELECT ,导致数据库压力翻倍。不准概略逻辑删除过滤 :醒目: 手写 SQL 时,MP 不会自动拼接 deleted=0 ,必须手动在 XML 中加上。不准使用“魔法值”:Lambda 抒发式绝交: 使用字符串硬编码列名(如 queryWrapper.eq("user_name", "Jack") )。强制: 必须使用 Lambda 神气,21点app确保编译期类型检查。// 正确示例
this.lambdaQuery
.eq(User::getUserName, dto.getUserName)
.orderByDesc(User::getCreateTime)
.list;
五、 SQL 与性能优化圭表 (搞定 5% 的慢查询 Bug)强制: 但凡 like 查询,澳门娱乐网站严禁使用左污秽( %要道词 ),必须使用 右污秽 ( 要道词% ),不然索引失效。 likeRight("name", "张")❌ like("name", "张")保举: 针对大数据量表,绝交实践 select count(*) ,应通过业务逻辑或 Redis 爱戴总额。圭表: 尽量幸免多表 Join 。阿里规约提议:跳动 3 张表绝交 Join。对策: 分两次查询,在 Service 层使用 Map 拼装数据。六、 审计与推广功能C 1. 自动填充 (MetaObjectHandler)强制: 严禁手动爱戴 update_time 等大家字段。
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now);
}
}
2. 字段脱敏圭表: 手机号、身份证、密码等敏锐信息,在 Entity 或 VO 上合作 @TableField(select = false) 或自界说 Jackson 序列化器进行脱敏。
七、 投产前 Check List (临了 5% 的 Bug 阻挠)- **空指针检查**:`LambdaQuery` 传入参数前是否判断了 `null`?(或使用 `.condition`)
- **分页溢出**:是否设立了 `PaginationInnerInterceptor` 且确立了最大单页结束(如 500 条)?
- **字段对应**:Entity 里的字段在数据库中是否齐存在?(不存在的需加 `@TableField(exist = false)`)
- **日记检查**:`application-prod.yml` 是否关闭了 SQL 日记打印?(防护日记文献撑爆磁盘)
- **缓存同步**:要是使用了 Redis 缓存,`updateById` 后是否同步删除了缓存?
{jz:field.toptypename/}八 全量设立圭表已毕1. 中枢插件设立类 ( MybatisPlusConfig.java )本设立类集成了常用的插件,确保系统在大数据量下的安全与性能。
package com.yourcompany.project.common.config;
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
/** * MyBatis-Plus 全量尺度化设立 * 包含:分页、乐不雅锁、防全表袭击插件 * * @author 专科 Java 身手员 */ @Configuration @MapperScan("com.yourcompany.project.mapper") // 修改为你的 Mapper 现实旅途 public class MybatisPlusConfig {
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor;
// 1. 分页插件: 必须确立数据库类型,且提议放在插件链的最前边 // 自动防护分页超出总页数(溢出处理) PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); paginationInterceptor.setMaxLimit(500L); // 结束单页最大 500 条,防护内存溢出 interceptor.addInnerInterceptor(paginationInterceptor);
// 2. 乐不雅锁插件: 实体类合作 @Version 注解使用,防护并发突破 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor);
// 3. 防全表更新与删除插件: 绝交莫得 where 条目的 update/delete,散失紧要事故 interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor);
return interceptor; } }
2. 审计字段自动填充 ( MyMetaObjectHandler.java )已毕阿里巴巴规约中“大家字段和洽爱戴”的要求,搞定手动确立 create_time 等产生的遗漏 Bug。
package com.yourcompany.project.common.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/** * 自动化审计字段填充器 */ @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler {
@Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); // 填充创建时辰与更新时辰 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now); this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now); // 填充默许删除位(0: 未删除) this.strictInsertFill(metaObject, "deleted", Integer.class, 0); // 填充版块号(乐不雅锁开动值) this.strictInsertFill(metaObject, "version", Integer.class, 1); // 要是有安全框架(如 Spring Security),可动态填充面前登请托户 ID // Long userId = SecurityUtils.getUserId; // this.strictInsertFill(metaObject, "createBy", Long.class, userId); }
@Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); // 更新操作时,自动更新修改时辰 this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now); } }
3. 尺度化基类实体 ( BaseEntity.java )封装 100% 实体类齐需要具备的字段,减少代码冗余。
package com.yourcompany.project.common.entity;
import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import lombok.Data; import java.time.LocalDateTime;
@Data public abstract class BaseEntity {
/** * 主键: 雪花算法,搞定永别式 ID 惟一性 * ToStringSerializer: 搞定前端 JS 无法处理 19 位 Long 导致的精度丢失问题 */ @TableId(type = IdType.ASSIGN_ID) @JsonSerialize(using = ToStringSerializer.class) private Long id;
/** * 自动填充创建时辰 */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime;
/** * 自动填充更新时辰 */ @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime;
/** * 乐不雅锁版块号: 合作 OptimisticLockerInnerInterceptor 使用 */ @Version @TableField(fill = FieldFill.INSERT) private Integer version;
/** * 逻辑删除位: 合作 @TableLogic 使用 */ @TableLogic @TableField(fill = FieldFill.INSERT) private Integer deleted; }
| 分页 MaxLimit | 防护坏心申请 size=999999 撑爆 JVM 内存。| | BlockAttack | 防护因代码 Bug 或运维误操作导致 DELETE FROM table(无条目全表清空)。| | ToStringSerializer | 搞定雪花 ID 临了两位在浏览器里变 00 的经典前端精度 Bug。| | OptimisticLocker | 搞定高并发下“先读后写”导致的数据互相阴私(Lost Update)。| | StrictInsertFill | 保证所非凡据均有好意思满的审计跟踪(谁在什么时间创建的)。|
使用提议全局扫描 :请确保 MybatisPlusConfig 中的 @MapperScan 旅途与你现实的 Mapper 接口位置一致。设立文献同步 :在 application.yml 中开启逻辑删除全局设立( logic-delete-field: deleted )。YAML 合作 :YAML
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段
logic-delete-value: 1 logic-not-delete-value: 0
风雅圭表不是为了结束斥地速率,而是为了在 凌晨 3 点 不需要爬起来处理坐蓐事故。