不灭的焱

革命尚未成功,同志仍须努力 下载Java

作者:AlbertWen  添加时间:2026-03-09 19:58:32  修改时间:2026-03-09 21:51:22  分类:01.Vibe Coding (氛围编程)  编辑

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 代码生成器位置

Codegen_Common.java

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 使用建议

  1. 优先使用 TableDef:通过SysUserTableDef.SYS_USER 进行查询,避免字符串硬编码
  2. 合理使用批量操作:大批量数据使用saveBatchupdateBatchById
  3. 注意事务控制:涉及多表操作时使用@Transactional
  4. 逻辑删除:统一使用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;

十、参考资料