MyBatis-Flex 全面解析与实战教程:轻量高效的 MyBatis 增强方案

一、MyBatis-Flex 简介

1.1 什么是 MyBatis-Flex

MyBatis-Flex 是一款基于 MyBatis 的轻量级增强框架,旨在简化数据库操作、提升开发效率,同时保留 MyBatis 原生灵活性与高性能优势。它并非替代 MyBatis,而是通过增强 API、优化架构设计,解决 MyBatis 单表操作繁琐、查询条件构建复杂等问题,且全程无第三方依赖,稳定性与自主性更强。

与同类框架相比,MyBatis-Flex 以"轻量、灵活、高性能"为核心定位:无 MyBatis 拦截器、无 SQL 解析环节,性能较传统增强框架提升 5-10 倍以上;同时支持多表查询、逻辑删除、数据脱敏等企业级特性,兼顾快速开发与复杂业务场景需求。

1.2 与 MyBatis/MyBatis-Plus 的区别

特性 MyBatis MyBatis-Plus MyBatis-Flex
核心定位 原生 ORM,侧重 SQL 与代码分离 MyBatis 增强,功能全面 轻量增强,兼顾性能与灵活
第三方依赖 无 依赖 hutool 等工具包 仅依赖 MyBatis,无其他依赖
性能表现 原生高效 拦截器模式有性能损耗 无拦截器、无 SQL 解析,性能最优
特色功能 原生 SQL 控制 代码生成、条件构造器 字段权限、数据脱敏、多租户原生支持

二、环境搭建(Spring Boot 集成)

本节以 Spring Boot 2.x + MySQL 为例,手把手教你完成 MyBatis-Flex 集成,Spring Boot 3.x 仅需调整依赖名称,操作一致。

2.1 前提条件

  • JDK 8+(Spring Boot 3.x 需 JDK 17+)

  • 熟悉 Spring Boot 基础配置与 Maven/Gradle 构建工具

  • 已安装 MySQL 数据库(5.7+)

2.2 创建数据库表

首先创建测试表 tb_account,并插入测试数据:

sql 复制代码
CREATE TABLE IF NOT EXISTS `tb_account` (
  `id` INTEGER PRIMARY KEY auto_increment COMMENT '主键ID',
  `user_name` VARCHAR(100) NOT NULL COMMENT '用户名',
  `age` INTEGER COMMENT '年龄',
  `birthday` DATETIME COMMENT '生日',
  `is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除标识(0-未删,1-已删)',
  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT '用户账户表';

INSERT INTO tb_account(user_name, age, birthday)
VALUES ('张三', 18, '2020-01-11'),
       ('李四', 19, '2021-03-21'),
       ('王五', 22, '2019-07-05');

2.3 添加 Maven 依赖

在 Spring Boot 项目的pom.xml 中添加以下依赖:

xml 复制代码
<dependencies/>
  <!-- MyBatis-Flex Spring Boot 启动器 -->
  <dependency>
    <groupId>com.mybatis-flex</groupId>
    <artifactId>mybatis-flex-spring-boot-starter</artifactId/>
    <version/>1.11.4</version/> <!-- 建议使用最新稳定版 -->
  </dependency/>

  <!-- MySQL 驱动 -->
  <dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
  </dependency/>

  <!-- 数据库连接池(HikariCP,Spring Boot 默认) -->
  <dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
  </dependency/>

  <!-- Lombok 简化实体类(可选,推荐) -->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
  </dependency/>

  <!-- 测试依赖 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

提示:若使用 Spring Boot 3.x,需将 mybatis-flex-spring-boot-starter 替换为 mybatis-flex-spring-boot3-starter。

2.4 配置数据源与 MyBatis-Flex

在 application.yml 中配置数据源和 MyBatis-Flex 基础参数:

yaml 复制代码
spring:
  # 数据源配置
  datasource:
    url: jdbc:mysql://localhost:3306/flex_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    username: root
    password: 12345678
    driver-class-name: com.mysql.cj.jdbc.Driver

# MyBatis-Flex 配置(可选,默认已适配大部分场景)
mybatis-flex:
  # 实体类扫描路径
  entity-scan: com.mybatisflex.test.entity
  # Mapper 接口扫描路径(也可通过 @MapperScan 注解配置)
  mapper-locations: classpath:mappers/**/*.xml
  # 开启 SQL 日志打印(开发环境推荐开启)
  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.5 配置启动类

在 Spring Boot 启动类上添加 @MapperScan 注解,扫描 Mapper 接口所在包:

java 复制代码
package com.mybatisflex.test;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.mybatisflex.test.mapper") // Mapper 接口路径
public class MybatisFlexTestApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisFlexTestApplication.class, args);
    }
}

三、基础用法实战

3.1 编写实体类(Entity)

使用 MyBatis-Flex 注解映射数据库表与字段,支持主键策略、逻辑删除、字段填充等配置:

java 复制代码
package com.mybatisflex.test.entity;

import com.mybatisflex.annotation.*;
import lombok.Data;
import java.util.Date;

@Data // Lombok 注解,自动生成 getter/setter
@Table("tb_account") // 映射数据库表名
@TableLogic(value = "0", deletedValue = "1") // 逻辑删除:未删0,已删1
public class Account {
    // 主键,自增策略
    @Id(keyType = KeyType.Auto)
    private Long id;

    // 字段名与数据库一致,可省略 @Column
    private String userName;

    private Integer age;

    private Date birthday;

    // 逻辑删除字段,与 @TableLogic 配合使用
    private Integer isDeleted;

    // 自动填充创建时间(插入时触发)
    @Column(fill = FillInsert.class)
    private Date createTime;
}

核心注解说明:

  • @Table:指定实体类对应数据库表名,支持逻辑删除全局配置。

  • @Id:标识主键,keyType 支持自增(Auto)、UUID、雪花算法等。

  • @Column:配置字段属性,fill 支持插入/更新时自动填充。

3.2 编写 Mapper 接口

Mapper 接口继承 MyBatis-Flex 提供的 BaseMapper,即可获得全套单表 CRUD 方法,无需编写 XML 或注解:

java 复制代码
package com.mybatisflex.test.mapper;

import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.test.entity.Account;
import org.springframework.stereotype.Repository;

// @Repository 注解用于 Spring 扫描管理
@Repository
public interface AccountMapper extends BaseMapper<Account> {
    // 无需额外编写方法,BaseMapper 已提供全套单表操作
}

BaseMapper核心方法包括:insert(新增)、update(更新)、deleteById(按ID删除)、selectById(按ID查询)、selectList(查询列表)等。

3.3 测试单表 CRUD 操作

编写单元测试,验证基础 CRUD 功能,注入 AccountMapper 即可调用方法:

java 复制代码
package com.mybatisflex.test;

import com.mybatisflex.test.entity.Account;
import com.mybatisflex.test.mapper.AccountMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
import java.util.List;

@SpringBootTest
public class AccountMapperTest {
    @Autowired
    private AccountMapper accountMapper;

    // 新增测试
    @Test
    public void testInsert() {
        Account account = new Account();
        account.setUserName("赵六");
        account.setAge(25);
        account.setBirthday(new Date());
        // 调用 BaseMapper 自带方法
        int rows = accountMapper.insert(account);
        System.out.println("新增行数:" + rows + ",新增ID:" + account.getId());
    }

    // 按ID查询测试
    @Test
    public void testSelectById() {
        Account account = accountMapper.selectById(1L);
        System.out.println("查询结果:" + account);
    }

    // 条件查询测试
    @Test
    public void testSelectList() {
        // 使用 QueryWrapper 构建查询条件
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(Account::getAge).gt(18) // 年龄大于18
                .and(Account::getUserName).like("张"); // 用户名包含"张"
        List<Account> accounts = accountMapper.selectListByQuery(queryWrapper);
        System.out.println("条件查询结果:" + accounts);
    }

    // 更新测试
    @Test
    public void testUpdate() {
        Account account = new Account();
        account.setId(1L);
        account.setAge(19); // 修改年龄
        int rows = accountMapper.update(account);
        System.out.println("更新行数:" + rows);
    }

    // 逻辑删除测试(实际执行 UPDATE,而非 DELETE)
    @Test
    public void testDeleteById() {
        int rows = accountMapper.deleteById(2L);
        System.out.println("删除行数:" + rows);
    }
}

四、核心特性详解

4.1 灵活的 QueryWrapper 条件构造器

MyBatis-Flex 提供的 QueryWrapper 支持链式调用,可构建复杂查询条件,包括多表关联、排序、分页等,且语法简洁易懂:

java 复制代码
// 1. 多条件组合查询
QueryWrapper queryWrapper = QueryWrapper.create()
        .select(Account::getId, Account::getUserName, Account::getAge) // 只查询指定字段
        .from(Account.class)
        .where(Account::getAge).between(18, 30) // 年龄在18-30之间
        .and(Account::getUserName).notLike("李") // 排除用户名含"李"的记录
        .orderBy(Account::getCreateTime).desc(); // 按创建时间倒序

// 2. 分页查询(第1页,每页10条)
Page<Account> page = accountMapper.paginate(1, 10, queryWrapper);
System.out.println("总条数:" + page.getTotalRows());
System.out.println("分页数据:" + page.getRecords());

// 3. 多表关联查询(示例:关联订单表,查询用户及对应订单数)
QueryWrapper joinQuery = QueryWrapper.create()
        .select(Account::getId, Account::getUserName)
        .select("COUNT(order.id) as order_count")
        .from(Account.class)
        .leftJoin(Order.class).on(Account::getId, Order::getAccountId)
        .groupBy(Account::getId)
        .having("order_count > 0");

4.2 批量操作优化

MyBatis-Flex 提供高效批量插入/更新方法,底层优化 SQL 执行效率,避免循环单条操作的性能问题:

java 复制代码
// 批量插入
@Test
public void testInsertBatch() {
    List<Account/> accountList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        Account account = new Account();
        account.setUserName("批量用户" + i);
        account.setAge(20 + i);
        account.setBirthday(new Date());
        accountList.add(account);
    }
    // 批量插入,返回成功行数
    int rows = accountMapper.insertBatch(accountList);
    System.out.println("批量插入行数:" + rows);
}

// 批量更新(按ID更新)
@Test
public void testUpdateBatch() {
    List<Account> accountList = accountMapper.selectListByQuery(QueryWrapper.create().where(Account::getAge).lt(20));
    accountList.forEach(account -> account.setAge(20)); // 统一将年龄改为20
    int rows = accountMapper.updateBatch(accountList);
    System.out.println("批量更新行数:" + rows);
}

4.3 数据脱敏与字段权限控制

4.3.1 数据脱敏

通过 @DataMask 注解实现字段脱敏,支持姓名、手机号、邮箱等常见场景,查询时自动脱敏,不影响数据库存储:

java 复制代码
import com.mybatisflex.annotation.DataMask;
import com.mybatisflex.annotation.DataMaskType;

public class Account {
    // 其他字段省略...
    
    // 姓名脱敏:保留姓氏,名字替换为*(如"张三"→"张*")
    @DataMask(type = DataMaskType.NAME)
    private String userName;

    // 手机号脱敏:保留前3位和后4位(如"13800138000"→"138****8000")
    @DataMask(type = DataMaskType.MOBILE)
    private String phone;
}

4.3.2 字段权限控制

通过 @Table 注解的 fieldPermission 属性,基于角色控制字段访问权限,适用于多角色场景:

java 复制代码
@Table(value = "tb_account", fieldPermission = {
        @FieldPermission(role = "admin", columns = {"*"}), // 管理员可查看所有字段
        @FieldPermission(role = "user", columns = {"id", "userName", "age"}) // 普通用户仅查看部分字段
})
public class Account {
    // 字段定义省略...
}

使用时需设置当前角色,查询时自动过滤无权限字段:

java 复制代码
// 设置当前角色为普通用户
QueryWrapper queryWrapper = QueryWrapper.create()
        .setRole("user")
        .where(Account::getAge).gt(18);
List<Account> accounts = accountMapper.selectListByQuery(queryWrapper);
// 返回结果仅包含 id、userName、age 字段

4.4 多租户支持

MyBatis-Flex 原生支持多租户,通过配置 TenantHandler 自动为查询、新增、更新操作添加租户条件,无需手动拼接:

java 复制代码
// 1. 实现 TenantHandler 接口
public class MyTenantHandler implements TenantHandler {
    // 租户ID字段名(数据库表中需包含该字段,如 tenant_id)
    @Override
    public String getTenantIdColumn() {
        return "tenant_id";
    }

    // 获取当前租户ID(实际场景从上下文获取,如登录用户信息)
    @Override
    public Object getTenantId() {
        return SecurityUtils.getCurrentTenantId(); // 自定义方法,获取当前租户ID
    }
}

// 2. 配置多租户(全局生效)
@Configuration
public class MyBatisFlexConfig {
    @Bean
    public MyBatisFlexCustomizer myBatisFlexCustomizer() {
        return config -> {
            config.setTenantHandler(new MyTenantHandler());
        };
    }
}

配置后,所有操作自动添加 tenant_id = 当前租户ID 条件,无需修改现有代码,实现租户数据隔离。

五、高级配置与最佳实践

5.1 自定义 SQL 与 XML 映射

MyBatis-Flex 支持原生 MyBatis XML 映射,适合复杂 SQL 场景,可与增强功能混用。例如,在 AccountMapper.xml 中编写自定义 SQL:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatisflex.test.mapper.AccountMapper"/>
    <!-- 自定义查询:查询指定年龄段的用户数量 -->
    <select id="countByAgeRange" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM tb_account
        WHERE age BETWEEN #{minAge} AND #{maxAge}
        AND is_deleted = 0
    </select>
</mapper>

在 Mapper 接口中添加对应方法:

java 复制代码
public interface AccountMapper extends BaseMapper<Account> {
    // 自定义方法,与 XML 中 id 对应
    Integer countByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);
}

5.2 性能优化建议

  • 批量操作优先使用 insertBatch/updateBatch,替代循环单条操作,减少数据库连接次数。

  • 复杂查询优先使用 XML 自定义 SQL,简单查询用QueryWrapper,平衡开发效率与性能。

  • 启用 MyBatis 二级缓存(针对静态数据),减少重复查询:在 Mapper 接口添加 @CacheNamespace 注解。

  • 忽略无需持久化的字段,通过 @Column(ignore = true) 标注,避免多余字段参与 SQL 构建。

5.3 常见问题排查

  • 字段映射失败 :检查实体类注解 @Table、@Column 是否正确,数据库字段名与实体类字段名是否一致(可开启 SQL 日志排查生成的 SQL)。

  • 逻辑删除不生效 :确保实体类添加@TableLogic 注解,且逻辑删除字段类型与配置值一致(如 TINYINT 对应 0/1)。

  • 多租户条件未添加 :检查 TenantHandler 实现是否正确,当前租户 ID 是否能正常获取,确保配置类被 Spring 扫描。

六、总结

MyBatis-Flex 作为一款轻量级 MyBatis 增强框架,既保留了原生 MyBatis 的灵活性与高性能,又通过简洁的 API、丰富的企业级特性,大幅降低了日常开发工作量。其无第三方依赖、无性能损耗的设计,使其在中小型项目快速开发与大型项目复杂场景中均能适用。

对于从 MyBatis 迁移的项目,MyBatis-Flex 可平滑集成,无需修改现有 XML 与 SQL;对于新项目,其 QueryWrapper、批量操作、多租户等特性,能有效提升开发效率,同时保持对 SQL 的绝对控制。建议在实际开发中根据业务场景灵活运用其增强功能,平衡开发效率与系统性能。

更多细节可参考官方文档:https://mybatis-flex.com/。

相关推荐
别动我齐刘海10 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
code2cat12 小时前
Java进阶篇之AtomicLongFieldUpdater:把累计额度留在对象字段中
java·cas·并发编程
WeiXin_DZbishe12 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
泡茶喝茶写代码12 小时前
A股量化数据工程:从 REST 接口到策略信号(第 18 篇):放量缩量异动扫描
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
wewowilling12 小时前
认识微服务
java·运维·微服务·springcloud
代码什么用13 小时前
Java Web 7-10
java·servlet
蜗牛互联网14 小时前
GPT-6 与 Intelligent UI:从回答到可审计操作的产品迁移
java·人工智能·后端
SL_staff15 小时前
运维救火实录:钉钉考勤API变更引发工资计算异常,我们用JVS-Logic可视化逻辑引擎实现分钟级热修复
java·mysql·全栈
SunnyDays101115 小时前
Java 查找并高亮 Word 文字:精确查找及正则表达式模糊查找
java·查找文字·word 文档·高亮文字·正则匹配查找·模糊查找