AI学习MyBatis-Flex ORM框架
项目中的 MyBatis-Flex 架构
1. 基础结构
<code class="language-text">fuyo-common/
├── entity/ # 实体类
│ ├── SysUser.java # 实体(带 @Table、@Id 注解)
│ └── table/ # 表定义(TableDef,类型安全的查询条件)
│ └── SysUserTableDef.java
├── mapper/ # Mapper 接口(继承 BaseMapper)
│ └── SysUserMapper.java
└── service/ # Service 接口和实现
├── SysUserService.java
└── impl/
└── SysUserServiceImpl.java
</code>
2. 核心代码说明
实体类 (SysUser.java)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_user") // 指定数据库表名
public class SysUser implements Serializable {
@Id(keyType = KeyType.Auto) // 主键,自增
private BigInteger id;
private String username;
private String nickname;
private Integer status;
// ... 其他字段
}
Mapper 接口 (SysUserMapper.java)
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
// BaseMapper 已提供常用的 CRUD 方法
}
Service 实现 (SysUserServiceImpl.java)
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
implements SysUserService {
// ServiceImpl 已提供丰富的业务操作方法
}
表定义 (SysUserTableDef.java)
public class SysUserTableDef extends TableDef {
public static final SysUserTableDef SYS_USER = new SysUserTableDef();
// 字段定义,用于类型安全的查询
public final QueryColumn ID = new QueryColumn(this, "id");
public final QueryColumn USERNAME = new QueryColumn(this, "username");
public final QueryColumn STATUS = new QueryColumn(this, "status");
// ... 其他字段
private SysUserTableDef() {
super("", "sys_user");
}
}
一、条件构造器(QueryWrapper)
MyBatis-Flex 提供了强大的条件构造器 QueryWrapper,配合 TableDef 实现类型安全的查询。
QueryWrapper 核心特点:
- 类型安全:通过 TableDef 避免字符串硬编码
- 链式调用:流畅的 API 设计
- 条件组合:支持复杂的 AND/OR 逻辑
1.1 基础查询
import static com.fuyo.dic.common.entity.table.SysUserTableDef.SYS_USER;
// 查询单个用户
SysUser user = SysUserService.getById(1L);
// 根据条件查询单个
SysUser user = sysUserService.getOne(QueryWrapper.create()
.where(SYS_USER.USERNAME.eq("admin"));
1.2 列表查询
// 查询所有用户
List<SysUser> users = sysUserService.list();
// 条件查询 - 查询正常状态的用户
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.STATUS.eq(1))
.and(SYS_USER.DELETED.eq(0))
);
// 多条件查询
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.STATUS.eq(1))
.and(SYS_USER.SEX.eq(1)) // 性别:男
.and(SYS_USER.ORGANIZATION_ID.eq(10)) // 机构ID为10
.orderBy(SYS_USER.CREATE_TIME.desc()) // 按创建时间降序
);
// 模糊查询
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.USERNAME.like("admin%")) // 用户名以 admin 开头
.or(SYS_USER.NICKNAME.like("%管理员%")) // 昵称包含"管理员"
.and(SYS_USER.STATUS.eq(1))
);
1.3 范围查询
// IN 查询
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.ID.in(Arrays.asList(1L, 2L, 3L)))
.and(SYS_USER.STATUS.eq(1))
);
// BETWEEN 查询
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.CREATE_TIME.between(
LocalDateTime.of(2024, 1, 1, 0, 0),
LocalDateTime.of(2024, 12, 31, 23, 59)
))
);
// 空值判断
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.EMAIL.isNull()) // 邮箱为空
.or(SYS_USER.PHONE.isNotNull()) // 手机号不为空
);
1.4 逻辑运算
// 复杂逻辑组合 (A AND B) OR (C AND D)
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.and(SYS_USER.STATUS.eq(1))
.and(SYS_USER.SEX.eq(1))
.or()
.and(SYS_USER.ORGANIZATION_ID.eq(10))
.and(SYS_USER.DELETED.eq(0))
);
// 使用 and() / or() 方法链式调用
QueryWrapper.create()
.where(SYS_USER.STATUS.eq(1))
.and(SYS_USER.SEX.eq(1))
.or(SYS_USER.ORGANIZATION_ID.eq(10))
.and(SYS_USER.DELETED.eq(0))
二、分页查询
2.1 基础分页
// 创建分页对象(第1页,每页10条)
Page<SysUser> page = sysUserService.page(Page.of(1, 10));
// 获取分页数据
List<SysUser> records = page.getRecords(); // 当前页数据
long total = page.getTotalRow(); // 总记录数
int totalPage = page.getTotalPage(); // 总页数
2.2 条件分页
// 带条件的分页查询
Page<SysUser> page = sysUserService.page(Page.of(1, 10), QueryWrapper.create()
.where(SYS_USER.STATUS.eq(1))
.and(SYS_USER.DELETED.eq(0))
.orderBy(SYS_USER.CREATE_TIME.desc())
);
2.3 分页排序
Page<SysUser> page = Page.of(1, 10);
page.orderBy(SYS_USER.CREATE_TIME.desc()); // 降序
// 多字段排序
page.orderBy(SYS_USER.STATUS.asc(), SYS_USER.CREATE_TIME.desc());
sysUserService.page(page, QueryWrapper.create()
.where(SYS_USER.DELETED.eq(0))
);
三、批量操作
3.1 批量插入
// 准备批量数据
List<SysUser> users = Arrays.asList(
SysUser.builder().username("user1").nickname("用户1").status(1).build(),
SysUser.builder().username("user2").nickname("用户2").status(1).build(),
SysUser.builder().username("user3").nickname("用户3").status(1).build()
);
// 批量插入(默认使用 JDBC Batch)
boolean success = sysUserService.saveBatch(users);
3.2 批量更新
// 方式1:构造实体列表进行批量更新
List<SysUser> users = Arrays.asList(
SysUser.builder().id(1L).nickname("用户1").status(0).build(),
SysUser.builder().id(2L).nickname("用户2").status(0).build()
);
boolean success = sysUserService.updateBatchById(users);
// 方式2:使用条件批量更新相同字段
int count = sysUserService.updateEntityByQuery(
SysUser.builder().status(0).build(), // 更新内容
QueryWrapper.create()
.where(SYS_USER.ORGANIZATION_ID.eq(10))
.and(SYS_USER.STATUS.eq(1))
);
3.3 批量删除
// 根据ID批量删除
boolean success = sysUserService.removeByIds(Arrays.asList(1L, 2L, 3L));
// 根据条件批量删除
int count = sysUserService.removeByQuery(QueryWrapper.create()
.where(SYS_USER.STATUS.eq(0))
.and(SYS_USER.DELETED.eq(0))
);
四、关联查询
4.1 一对一查询
// 查询用户及其机构信息
// 需要先定义关联表
// 方式1:使用 @Relation 注解(在 Entity 上配置)
// 方式2:手动关联查询
// 先查询用户列表
List<SysUser> users = sysUserService.list(QueryWrapper.create()
.where(SYS_USER.ORGANIZATION_ID.in(organizationIds))
);
// 批量查询机构
List<SysOrganization> organizations = organizationService.list(
QueryWrapper.create()
.where(SYS_ORGANIZATION.ID.in(
users.stream().map(SysUser::getOrganizationId).collect(Collectors.toList())
))
);
// 组装数据
Map<Long, SysOrganization> orgMap = organizations.stream()
.collect(Collectors.toMap(SysOrganization::getId, org -> org));
users.forEach(user -> user.setOrganization(orgMap.get(user.getOrganizationId())));
4.2 一对多查询
// 查询用户及其角色列表
// 先查询用户
List<SysUser> users = sysUserService.list();
// 批量查询用户角色关联
List<SysUserRole> userRoles = userRoleService.list(QueryWrapper.create()
.where(SYS_USER_ROLE.USER_ID.in(
users.stream().map(SysUser::getId).collect(Collectors.toList())
))
);
// 查询角色详情
List<Long> roleIds = userRoles.stream()
.map(SysUserRole::getRoleId)
.distinct()
.collect(Collectors.toList());
Map<Long, SysRole> roleMap = roleService.listByIds(roleIds).stream()
.collect(Collectors.toMap(SysRole::getId, role -> role));
// 组装数据
Map<Long, List<SysRole>> userRoleMap = userRoles.stream()
.collect(Collectors.groupingBy(
ur -> ur.getUserId(),
Collectors.mapping(ur -> roleMap.get(ur.getRoleId()), Collectors.toList())
));
五、聚合查询
5.1 统计函数
// 统计用户总数
long count = sysUserService.count();
// 条件统计
long count = sysUserService.count(QueryWrapper.create()
.where(SYS_USER.STATUS.eq(1))
);
// 使用 QueryWrapper 进行聚合查询
QueryWrapper qw = QueryWrapper.create()
.select(
SYS_USER.SEX,
SYS_USER.SEX.count().as("count") // 按性别统计
)
.groupBy(SYS_USER.SEX);
List<Map<String, Object>> result = sysUserService.listMaps(qw);
5.2 求和、平均值
// 统计每个机构的有效用户数
QueryWrapper qw = QueryWrapper.create()
.select(
SYS_USER.ORGANIZATION_ID,
SYS_USER.ID.count().as("user_count")
)
.where(SYS_USER.STATUS.eq(1))
.where(SYS_USER.DELETED.eq(0))
.groupBy(SYS_USER.ORGANIZATION_ID)
.having(SYS_USER.ID.count().gt(0));
List<Map<String, Object>> result = sysUserService.listMaps(qw);
六、常见使用场景示例
6.1 用户列表分页查询
public Page<SysUser> getUserListPage(int pageNum, int pageSize, String username,
Integer status, Long organizationId) {
QueryWrapper qw = QueryWrapper.create();
// 动态条件
if (StringUtils.isNotBlank(username)) {
qw.and(SYS_USER.USERNAME.like("%" + username + "%")
.or(SYS_USER.NICKNAME.like("%" + username + "%")));
}
if (status != null) {
qw.and(SYS_USER.STATUS.eq(status));
}
if (organizationId != null) {
qw.and(SYS_USER.ORGANIZATION_ID.eq(organizationId));
}
qw.and(SYS_USER.DELETED.eq(0))
.orderBy(SYS_USER.CREATE_TIME.desc());
return sysUserService.page(Page.of(pageNum, pageSize), qw);
}
6.2 用户导入(批量插入)
@Transactional
public void importUsers(List<SysUserVO> userVOs) {
List<SysUser> users = userVOs.stream().map(vo -> {
SysUser user = SysUser.builder()
.username(vo.getUsername())
.nickname(vo.getNickname())
.status(1)
.deleted(0)
.createTime(LocalDateTime.now())
.build();
// 密码加密
user.setPassword(passwordEncoder.encode(vo.getPassword()));
return user;
}).collect(Collectors.toList());
// 分批插入(每批500条)
int batchSize = 500;
for (int i = 0; i < users.size(); i += batchSize) {
int end = Math.min(i + batchSize, users.size());
sysUserService.saveBatch(users.subList(i, end), batchSize);
}
}
6.3 用户状态变更(批量更新)
public boolean updateUserStatus(List<Long> userIds, Integer status) {
return sysUserService.updateEntityByQuery(
SysUser.builder()
.status(status)
.updateTime(LocalDateTime.now())
.build(),
QueryWrapper.create()
.where(SYS_USER.ID.in(userIds))
.and(SYS_USER.DELETED.eq(0))
) > 0;
}
七、配置说明
7.1 项目配置 (application-dev.yml)
mybatis-flex:
datasource:
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.p6spy.engine.spy.P6SpyDriver # P6Spy SQL监控
url: jdbc:p6spy:mysql://...
username: xxx
password: xxx
druid:
initial-size: 5 # 初始连接数
min-idle: 5 # 最小空闲连接
max-active: 20 # 最大活跃连接
max-wait: 60000 # 最大等待时间
7.2 P6Spy SQL 日志
项目使用 P6Spy 进行 SQL 语句监控,所有 SQL 语句会在日志中输出,方便调试。
八、代码生成器
8.1 代码生成器位置
8.2 使用方法
# 方法1:使用 Maven 命令
mvn exec:java -Dexec.mainClass="com.fuyo.dic.Codegen_Common" -pl fuyo-codegen
# 方法2:在 IDE 中直接运行 Codegen_Common.main() 方法
8.3 配置说明
// 修改需要生成的表
String[] generateTable = {
"sys_user",
"sys_role",
// ...
};
// 修改数据库连接
String MySQL_URL = "jdbc:mysql://...";
String MySQL_USERNAME = "xxx";
String MySQL_PASSWORD = "xxx";
九、最佳实践
9.1 命名规范
- 实体类:
SysUser对应表sys_user - Mapper:
SysUserMapper继承BaseMapper<SysUser> - Service:
SysUserService继承IService<SysUser> - TableDef:
SysUserTableDef静态实例SYS_USER
9.2 使用建议
- 优先使用 TableDef:通过
SysUserTableDef.SYS_USER进行查询,避免字符串硬编码 - 合理使用批量操作:大批量数据使用
saveBatch、updateBatchById - 注意事务控制:涉及多表操作时使用
@Transactional - 逻辑删除:统一使用
deleted字段,避免物理删除
9.3 常用导入
import static com.fuyo.dic.common.entity.table.SysUserTableDef.SYS_USER;
import static com.fuyo.dic.common.entity.table.SysRoleTableDef.SYS_ROLE;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.mybatisflex.core.paginate.Page;