Mapper 数据访问
本文说明 ECShopX Java 持久化层的约定:MyBatis-Plus BaseMapper、domain 表映射注解、多 Bundle 下 Mapper Bean 命名,以及与 Flyway 迁移的分工。
分层关系
Controller / Service
↓
Repository(可选,如 ecshopx-goods)
↓
Mapper(extends BaseMapper<实体>)
↓
Domain(@MpTable / @MpField 表映射)
↓
MySQL- 结构变更(加列、改类型、索引):先改
domain→bin/make-migration→ review SQL → migrate(见 数据库快速入门) - 数据访问:Service 经 Mapper 或 Repository 读写,Controller 不直接注入 Mapper
Domain — 表映射实体
实体放在 ecshopx-<domain>/src/main/java/cn/shopex/ecshopx/<domain>/domain/。
推荐注解(本项目元数据)
项目扩展了 MyBatis-Plus 元数据注解,便于迁移脚本生成与文档化:
| 注解 | 作用 |
|---|---|
@MpTable | 表名、表注释、@MpIndex 索引声明 |
@MpField | 列名、类型、长度、nullable、默认值、注释 |
@MpId | 主键列与 IdType |
示例(ecshopx-goods 商品表):
@MpTable(value = "items", comment = "商品表", indexes = {
@MpIndex(name = "ix_company_id", columns = {"company_id"})
})
public class Items {
@MpId(value = "item_id", type = IdType.AUTO, columnType = "bigint", comment = "商品ID")
private Long itemId;
@MpField(value = "item_name", columnType = "string", length = 255, comment = "商品名称")
private String itemName;
// ...
}源文件:ecshopx-goods/src/main/java/cn/shopex/ecshopx/goods/domain/Items.java
兼容注解
bin/make-migration 同时识别 MyBatis-Plus 原生注解:
@TableName— 表名@TableId— 主键@TableField— 普通列
历史或简单实体可继续使用;新代码建议优先 @MpTable / @MpField,以便生成更完整的迁移 SQL 与索引元数据。
Mapper — BaseMapper
Mapper 接口放在 ecshopx-<domain>/.../mapper/,继承 com.baomidou.mybatisplus.core.mapper.BaseMapper<实体>,获得单表 CRUD 与 LambdaQueryWrapper 能力。
@Mapper
public interface ItemsMapper extends BaseMapper<Items> {
// 模块内可声明 @Select 等自定义 SQL
}源文件:ecshopx-goods/src/main/java/cn/shopex/ecshopx/goods/mapper/ItemsMapper.java
复杂、可复用的查询条件可封装到 repository 包(如 ItemsRepository),供 Service 注入。详见 Bundle。
多 Bundle:FqcnMapperBeanNameGenerator
50+ 业务模块中经常出现同名 XxxMapper 接口。默认 Spring Bean 名(如 itemsMapper)会冲突。
启动类 EcshopxApplication 在 @MapperScan 上指定 FqcnMapperBeanNameGenerator:
@MapperScan(
basePackages = "cn.shopex.ecshopx.**.mapper",
nameGenerator = FqcnMapperBeanNameGenerator.class,
sqlSessionFactoryRef = "sqlSessionFactory",
lazyInitialization = "true")生成规则:将 Mapper 全限定类名中的 . 替换为 _ 作为 Bean 名,例如:
cn.shopex.ecshopx.goods.mapper.ItemsMapper → cn_shopex_ecshopx_goods_mapper_ItemsMapper
新增 Mapper 时:放在 cn.shopex.ecshopx.<domain>.mapper 包下即可,无需手工处理 Bean 名冲突。
实现类:ecshopx-common/.../mybatis/FqcnMapperBeanNameGenerator.java
读写分离
架构层面支持 MySQL 读写分离与 PolarDB 等兼容实例(见 架构说明)。当前仓库未内置动态数据源路由;application.properties 仅配置单一 spring.datasource.* 数据源。
生产环境常见做法:
- 在 JDBC URL 或中间件(PolarDB 代理、ProxySQL 等)层做读写分离
- 或通过 Spring Boot 多数据源配置扩展(需自行引入,非本仓库默认能力)
本地开发与 Docker Compose 均使用单库连接,配置键:
| 配置键 | 说明 |
|---|---|
spring.datasource.url | JDBC URL |
spring.datasource.username | 用户名 |
spring.datasource.password | 密码 |
bin/make-migration 与 migrate 子命令读取同一套数据源配置(可用 --profile / --db-url 覆盖)。
禁止事项
| 禁止 | 说明 |
|---|---|
| Controller 直接注入 Mapper | 经 Service 或 Repository |
| 跨 Bundle 引用对方 Mapper | 通过 Port 暴露能力 |
| 手写与 Flyway 不一致的表结构 | 结构变更走迁移并同步 domain |
| 未 review 即执行生成的 SQL | 生成结果为 best-effort |
