You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
17 KiB

1 month ago
# 基础服务层
<cite>
**本文引用的文件**
- [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本章节面向“基础服务层”,聚焦以下目标:
- IBaseService 接口提供的通用CRUD、分页查询与批量操作能力
- BaseServiceImpl 的实现细节,包括事务管理、数据验证、异常处理
- CrmBaseMapper 对 MyBatis Plus 的扩展,如自定义SQL注入器、动态条件构建等高级特性
- 如何基于该基础层进行服务扩展与自定义业务逻辑实现
## 项目结构
基础服务层位于 crm-base 模块,围绕“接口-实现-Mapper-配置”分层组织:
- service/IBaseService:定义通用服务接口
- service/impl/BaseServiceImpl:通用服务实现
- mapper/CrmBaseMapper:扩展 MyBatis Plus Mapper
- config/*:MyBatis Plus 配置、SQL注入器、元对象填充、全局异常处理等
- domain/*:实体基类、结果封装、枚举、异常等
```mermaid
graph TB
subgraph "基础服务层"
IBase["IBaseService"]
Impl["BaseServiceImpl"]
Mapper["CrmBaseMapper"]
MPConf["MybatisPlusConfig"]
SQLI["CrmSqlInjector"]
Fill["MetaObjectFillHandler"]
ExAd["GlobalExceptionHandlerAdvice"]
Result["Result / PageResult"]
BE["BaseEntity / OwnedEntity"]
end
IBase --> Impl
Impl --> Mapper
Impl --> Result
Impl --> BE
Mapper --> MPConf
MPConf --> SQLI
MPConf --> Fill
ExAd --> Result
```
图表来源
- [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
章节来源
- [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
## 核心组件
- IBaseService:定义通用CRUD、分页查询、批量操作的统一接口契约,供各业务服务继承或组合使用。
- BaseServiceImpl:基于 MyBatis Plus 的 ServiceImpl 提供默认实现,封装事务、参数校验、异常转换、分页与批量方法。
- CrmBaseMapper:扩展 MyBatis Plus 的 BaseMapper,提供统一的查询构造、动态条件、批量操作等能力。
- MybatisPlusConfig + CrmSqlInjector:注册自定义SQL注入器,为Mapper注入通用方法(如动态条件查询、批量插入更新)。
- MetaObjectFillHandler:自动填充审计字段(创建时间、更新时间、创建人等),保证数据一致性。
- GlobalExceptionHandlerAdvice:统一异常捕获与响应封装,将业务异常转换为标准 Result 返回。
章节来源
- [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
## 架构总览
下图展示了从控制器到服务层再到数据访问层的调用链,以及基础服务层在其中的作用。
```mermaid
sequenceDiagram
participant C as "控制器"
participant S as "业务服务(继承IBaseService)"
participant BS as "BaseServiceImpl"
participant M as "CrmBaseMapper"
participant DB as "数据库"
C->>S : "调用CRUD/分页/批量方法"
S->>BS : "委托通用实现"
BS->>BS : "参数校验/事务边界"
BS->>M : "执行SQL(含动态条件/批量)"
M-->>BS : "返回结果集/影响行数"
BS-->>S : "封装Result/PageResult"
S-->>C : "统一响应"
```
图表来源
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
## 详细组件分析
### IBaseService 接口设计
- 职责:定义通用CRUD、分页查询、批量操作的方法签名,确保各业务服务具备一致的数据访问能力。
- 典型能力:
- 单条/批量新增、修改、删除
- 按ID获取、条件查询、分页查询
- 批量更新(支持部分字段)
- 返回统一结果类型(Result/PageResult)
- 设计要点:
- 泛型约束实体类型,便于类型安全
- 输入参数与输出结果采用DTO/Param/VO分离,避免泄露内部模型
- 分页查询返回 PageResult,包含数据列表与分页信息
章节来源
- [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java)
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
### BaseServiceImpl 实现细节
- 事务管理:
- 关键写操作(新增、修改、删除、批量)包裹在事务中,保证原子性
- 读操作通常非事务或只读事务,减少锁竞争
- 数据验证:
- 入参非空校验、业务规则校验(如唯一性检查)
- 结合实体注解与自定义校验器,统一错误提示
- 异常处理:
- 捕获并转换底层异常为业务异常
- 通过全局异常处理器统一封装为 Result
- 分页与批量:
- 分页查询使用 MyBatis Plus 的分页插件,配合动态条件构建
- 批量操作优先使用批处理器,降低往返开销
- 审计字段填充:
- 借助 MetaObjectFillHandler 自动填充创建/更新时间、操作人等
```mermaid
flowchart TD
Start(["进入写方法"]) --> Check["参数校验"]
Check --> Valid{"校验通过?"}
Valid --> |否| Err["抛出业务异常"]
Valid --> |是| TxStart["开启事务"]
TxStart --> Exec["执行持久化操作"]
Exec --> Success{"是否成功?"}
Success --> |否| Rollback["回滚事务"]
Success --> |是| Commit["提交事务"]
Commit --> End(["返回结果"])
Rollback --> End
Err --> End
```
图表来源
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
章节来源
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
### CrmBaseMapper 与 MyBatis Plus 扩展
- 扩展点:
- 继承 MyBatis Plus 的 BaseMapper,提供通用CRUD能力
- 通过自定义 SQL 注入器注入动态条件查询、批量方法
- 动态条件构建:
- 支持多条件组合(等于、模糊、范围、IN等)
- 可结合实体属性生成 WHERE 片段,避免手写SQL
- 批量操作:
- 批量插入/更新,利用数据库特性优化性能
- 支持 ON DUPLICATE KEY UPDATE 或 MERGE 语义(由注入器决定)
- 分页查询:
- 与分页插件集成,自动拼接 LIMIT/OFFSET 或等效语法
```mermaid
classDiagram
class CrmBaseMapper {
+selectListByCondition(query) List
+insertBatch(list) int
+updateBatchById(list) int
+deleteByIds(ids) int
}
class MybatisPlusConfig {
+registerSqlInjector()
+paginationInterceptor()
}
class CrmSqlInjector {
+addCustomMethod()
}
CrmBaseMapper --> MybatisPlusConfig : "被配置注册"
MybatisPlusConfig --> CrmSqlInjector : "注入自定义方法"
```
图表来源
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
章节来源
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
### 实体基类与审计字段
- BaseEntity:
- 定义通用字段(如主键、状态、删除标记等)
- 与填充处理器协作,自动维护审计字段
- OwnedEntity:
- 在 BaseEntity 基础上增加数据权限相关字段(如所属部门、归属人)
- 配合数据可见性上下文,实现行级权限控制
```mermaid
classDiagram
class BaseEntity {
+id
+createTime
+updateTime
+creator
+updater
}
class OwnedEntity {
+ownerId
+deptId
}
BaseEntity <|-- OwnedEntity
```
图表来源
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
章节来源
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
## 依赖关系分析
- 组件耦合:
- BaseServiceImpl 依赖 CrmBaseMapper 完成数据访问
- MybatisPlusConfig 负责装配 CrmSqlInjector 与分页插件
- MetaObjectFillHandler 与实体基类协作完成审计字段填充
- GlobalExceptionHandlerAdvice 统一捕获异常并封装为 Result
- 外部依赖:
- MyBatis Plus:ORM框架、分页插件、SQL注入机制
- 数据库驱动:具体SQL方言由注入器适配
```mermaid
graph LR
Impl["BaseServiceImpl"] --> Mapper["CrmBaseMapper"]
Mapper --> MPConf["MybatisPlusConfig"]
MPConf --> SQLI["CrmSqlInjector"]
Impl --> Fill["MetaObjectFillHandler"]
Impl --> Ex["GlobalExceptionHandlerAdvice"]
Impl --> Res["Result/PageResult"]
```
图表来源
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
章节来源
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
- [CrmBaseMapper.java](file://crm-base/src/main/java/com/crm/base/mapper/CrmBaseMapper.java)
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
- [CrmSqlInjector.java](file://crm-base/src/main/java/com/crm/base/config/CrmSqlInjector.java)
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
## 性能考量
- 分页查询:
- 使用分页插件避免全表扫描,合理设置 page/size
- 复杂条件查询建议建立合适索引
- 批量操作:
- 优先使用批量插入/更新,减少网络往返
- 大批量数据分片提交,避免单次事务过大
- 事务边界:
- 缩小事务范围,避免长事务导致锁竞争
- 读多写少场景尽量使用只读事务
- 填充与校验:
- 审计字段填充在写入前完成,避免额外更新
- 校验失败尽早返回,减少无效DB交互
[本节为通用指导,不直接分析具体文件]
## 故障排查指南
- 常见异常:
- 参数校验失败:检查入参非空与业务规则
- 事务回滚:查看日志中的异常堆栈,定位失败SQL或约束冲突
- 分页异常:确认分页参数合法性与排序字段存在
- 调试建议:
- 开启 MyBatis SQL 日志,观察实际执行的SQL
- 使用全局异常处理器返回的 Result 快速定位错误码与消息
- 针对批量操作,逐步缩小批次大小定位问题
章节来源
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
- [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java)
## 结论
基础服务层通过 IBaseService 与 BaseServiceImpl 提供了稳定、一致的CRUD与分页、批量能力;CrmBaseMapper 与自定义 SQL 注入器增强了动态条件与批量处理能力;MetaObjectFillHandler 与全局异常处理完善了数据一致性与用户体验。在此基础上,业务服务只需关注领域逻辑,即可快速实现高质量的数据访问层。
[本节为总结,不直接分析具体文件]
## 附录
- 扩展建议:
- 在 CrmSqlInjector 中按需添加更多通用方法(如软删除、逻辑删除)
- 在 BaseServiceImpl 中扩展复杂业务校验与补偿逻辑
- 结合缓存策略提升热点数据读取性能
- 最佳实践:
- 严格区分 DTO/Param/VO,避免实体泄漏
- 分页查询避免深分页,必要时使用游标或延迟加载
- 批量操作注意内存占用与事务大小平衡
[本节为补充说明,不直接分析具体文件]