MyBatis-Flex: 优雅永不过时, 你值得拥有

一.  MyBatis-Flex 到底是啥?凭啥用它?

想象一下 MyBatis 的灵活 + APT,揉在一起,就是 MyBatis-Flex!它的核心卖点:

  • 无 XML!无 XML!无 XML! 重要的事情说三遍!所有 SQL 动态生成都在 Java 代码里搞定,告别繁琐的 XML 配置和手写 SQL 语句(当然,复杂 SQL 想写也支持)。

  • 超灵活的 QueryWrapper: 基于 Lambda 表达式构建查询条件,链式调用类型安全代码即 SQL,IDE 智能提示爽歪歪。再也不用怕字段名拼错了!

  • 极致性能: APT(Annotation Processing Tool)代码生成 + 精心优化的 SQL 生成逻辑,性能杠杠的,尤其在大数据量、复杂查询场景下优势明显。

  • 强大的多表支持: 关联查询 (1v11vNNvN) 配置简单,查询高效,支持 JOIN 和 子查询 两种模式。

  • 丰富的功能: 逻辑删除、多租户、字段权限控制(数据脱敏)、乐观锁、数据填充... 该有的都有。

  • 轻量级: 核心依赖极小,只依赖 MyBatis,启动快,内存占用低。

  • 开发者阿里巴巴腾讯科大讯飞、 网宿科技新东方 等企业的同学+学生

一句话总结: 用更现代、更优雅、更高效的方式玩转 MyBatis!

二、Spring Boot 3 + MyBatis-Flex:光速启动!

2.1 添加pom.xml 依赖.

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.2.0</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.mybatis-flex</groupId>
            <artifactId>mybatis-flex-spring-boot3-starter</artifactId>
            <version>1.10.9</version>
        </dependency>


        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>4.0.3</version>
        </dependency>


      <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                         <!--  生成APT 代码的关键-->
                        <path>
                            <groupId>com.mybatis-flex</groupId>
                            <artifactId>mybatis-flex-processor</artifactId>
                            <version>1.10.9</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
         </plugins>
      </build>

2.2 application,yml 配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flex_test?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
    username: root
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

 2.3 创建实体类 (Account.java)

注意 @Table 和 @Column 注解! APT 靠它们生成代码

@Data
@Table("tb_account") // 指定表名
public class Account {

    @Id(keyType = KeyType.Auto) // 主键,自增
    private Long id;

    @Column("user_name") // 指定列名
    @ColumnMask(Masks.CHINESE_NAME)  // 数据脱敏
    private String userName;

    private Integer age;
    private Date birthday;
    private BigDecimal balance;

    
}

审计sql日志

@Configuration
public class MyBatisFlexConfiguration {

    private static final Logger logger = LoggerFactory
        .getLogger("mybatis-flex-sql");


    public MyBatisFlexConfiguration() {
        //开启审计功能
        AuditManager.setAuditEnable(true);

        //设置 SQL 审计收集器
        AuditManager.setMessageCollector(auditMessage ->
            logger.info("{},{}ms", auditMessage.getFullSql()
                , auditMessage.getElapsedTime())
        );
    }
}

2.4 创建 Mapper 接口 (AccountMapper.java)

public interface AccountMapper extends BaseMapper<Account> {
    // 这里可以定义自己的复杂查询方法,后面会讲到
}

2.5 启动类

@SpringBootApplication
@MapperScan("com.yourpackage.mapper") // 扫描你的 Mapper 接口
public class FlexDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(FlexDemoApplication.class, args);
    }
}

三. 基础 CRUD:简单到哭!

得益于 BaseMapper,基本的增删改查直接起飞 🛫。

@Autowired
private AccountMapper accountMapper;

// 插入 (返回主键会自动填充到 entity.id)
accountMapper.insert(account);

// 根据 ID 查询
Account account = accountMapper.selectOneById(1L);

// 更新 (根据主键)
account.setUserName("NewName");
accountMapper.update(account);

// 删除 (根据主键)
accountMapper.deleteById(1L);

// 查询所有
List<Account> accounts = accountMapper.selectAll();

3.1. QueryWrapper:Lambda 链式编程,优雅永不过时!

这才是 Flex 的灵魂所在! 用 Lambda 表达式构建查询条件,类型安全,IDE 友好。

// 导入静态方法方便链式调用
import static com.mybatisflex.core.query.QueryMethods.*;

// 查询年龄大于18,用户名包含"Tom",按余额降序
QueryWrapper query = QueryWrapper.create()
    .select() // 查询所有列
    .from(ACCOUNT) // 使用静态导入的 ACCOUNT 对象 (由APT生成)
    .where(ACCOUNT.AGE.ge(18)) // age >= 18
    .and(ACCOUNT.USER_NAME.like("Tom%")) // AND user_name LIKE 'Tom%'
    .orderBy(ACCOUNT.BALANCE.desc()); // ORDER BY balance DESC

List<Account> accounts = accountMapper.selectListByQuery(query);

看这段代码!

  • ACCOUNT 是一个由 APT 自动生成的 静态常量对象,对应 tb_account 表及其所有字段。

  • ACCOUNT.AGE.ge(18) -> age >= 18

  • ACCOUNT.USER_NAME.like("Tom%") -> user_name LIKE 'Tom%'

  • 链式调用,清晰明了。

  • 完全类型安全! AGE 是数字类型,USER_NAME 是字符串类型。写 ACCOUNT.AGE.like("Tom")?编译直接报错!告别字段名拼写错误!

  • IDE 智能提示爽到飞起!

query.where(ACCOUNT.ID.in(1, 2, 3)); // IN
query.where(ACCOUNT.BIRTHDAY.between(startDate, endDate)); // BETWEEN
query.where(ACCOUNT.BALANCE.isNotNull()); // IS NOT NULL
query.groupBy(ACCOUNT.AGE); // GROUP BY
query.having(sum(ACCOUNT.BALANCE).gt(10000)); // HAVING

 动态SQL 也超级简单

QueryWrapper query = QueryWrapper.create()
    .select().from(ACCOUNT);

if (age != null) {
    query.and(ACCOUNT.AGE.eq(age));
}
if (StringUtils.isNotBlank(userName)) {
    query.and(ACCOUNT.USER_NAME.like(userName + "%"));
}

 3.2. 分页:一行代码搞定,性能还贼强!

Flex 的分页设计非常高效,内置支持多种数据库分页语法,自动优化 COUNT 查询

// 第2页,每页10条
Page<Account> page = Page.of(2, 10);

// 构建查询条件
QueryWrapper query = QueryWrapper.create()
    .where(ACCOUNT.AGE.gt(20));

// 执行分页查询 (关键方法: paginateAs)
Page<Account> result = accountMapper.paginateAs(page, query, Account.class);

// 结果
System.out.println("总记录数: " + result.getTotalRow());
System.out.println("总页数: " + result.getTotalPage());
List<Account> records = result.getRecords(); // 当前页数据

paginateAs 这一行代码就搞定了分页查询和总记录数查询!

性能优化点: 对于复杂的查询,Flex 会智能判断是否需要对原查询进行优化(例如去掉不必要的 ORDER BY)来执行 COUNT 查询,提升性能。对于简单的 WHERE 条件,COUNT 查询就是 SELECT COUNT(*) FROM ...

3.3. Relations:关联查询,告别 N+1!

查询 Account 时想同时查出它关联的 Order 列表?Flex 的关联注解轻松搞定。

 定义关联关系 (Account.java)

// 查询 Account 及其关联的 Orders (使用 Relations QueryWrapper)
QueryWrapper query = QueryWrapper.create()
    .select()
    .from(ACCOUNT)
    .where(ACCOUNT.ID.eq(1L))
    .withRelations(); // 关键:加载关联关系

// 执行查询 (使用 selectOneWithRelationsByQuery)
Account accountWithOrders = accountMapper.selectOneWithRelationsByQuery(query);

// 直接访问关联的订单
List<Order> orders = accountWithOrders.getOrders(); // 数据已加载好!

原理(两种模式):

  • JOIN 模式 (默认): 生成一条包含 LEFT JOIN 的大 SQL 一次性查出所有数据。Flex 会自动处理结果集映射,将关联数据组装到主对象的集合属性中。性能好,推荐使用。

  • 子查询 模式: 先查询主对象,再根据主对象 ID 批量查询关联对象(SELECT * FROM order WHERE account_id IN (?, ?, ...))。避免 N+1 问题。可以通过 @RelationXXX(extraCondition = ...) 或全局配置切换。

四. 🔥 深入核心:SQL Provider 原理揭秘 

大家有没有好奇,Flex 不用 XML,那些 QueryWrapper 对象是怎么变成最终执行的 SQL 语句的?秘密就在于 SQL Provider 和 APT

4.1 核心参与者

  • QueryWrapper 你写的查询条件构建器,包含了要查询的表、字段、条件、排序等信息。它是一个 结构化对象

  • BaseMapper 方法 (如 selectListByQuery): 这些方法需要一个 SQL 语句来执行。它们内部依赖于 @SelectProvider 注解。

  • @SelectProvider / @UpdateProvider 等注解: MyBatis 提供的机制,允许你指定一个类和方法来 动态生成 SQL 字符串

  • SqlProvider 类 (TableDefSqlProvider): Flex 提供的一个核心类。它的方法(如 selectByQuery)接收 QueryWrapper 对象作为参数。

  • QueryWrapper 的 toSQL() 方法: 这是关键!QueryWrapper 对象有能力将自己“翻译”成标准的 SQL 字符串及其参数。

  • TableDef (由 APT 生成): 就是你看到的 ACCOUNT 那个类。它包含了表名、所有字段名(字符串常量)、所有字段对应的 QueryColumn 对象(用于构建条件)。APT 在编译期间根据实体类的 @Table 和 @Column 注解自动生成这些类。这是类型安全和 IDE 提示的基础!

4.2 执行流程

 4.3 APT 的核心作用

  • 编译期生成 (AccountTableDef): APT 在编译时扫描 Account 类上的 @Table 和 @Column 注解,生成对应的 AccountTableDef 类。这个类包含:

    • 表名的字符串常量 (TABLE_NAME)。

    • 代表表本身的 QueryTable 对象 (TABLE)。

    • 代表表中每个字段的 QueryColumn 对象 (IDUSER_NAME 等)。这些对象知道自己属于哪个表、叫什么名字、是什么类型。

  • 运行时构建 (QueryWrapper): 你在代码中使用 ACCOUNT.ID.eq(1)

    • ACCOUNT 就是 AccountTableDef.TABLE (一个 QueryTable)。

    • ID 是 AccountTableDef.ID (一个 QueryColumn)。

    • eq(1) 方法调用 QueryColumn 的方法,返回一个 QueryCondition 对象。这个对象内部记录了 字段名(ID)操作符(=)值(1)

  • SQL 生成 (toSQL()): QueryWrapper 对象内部维护了要查询的表 (FROM)、选择的列 (SELECT)、条件 (WHERE)、排序 (ORDER BY) 等信息(这些信息就是由你链式调用添加进去的各种 QueryTableQueryColumnQueryCondition 对象组成的结构)。当调用 toSQL() 时,QueryWrapper 会遍历这个结构,按照 SQL 语法规则,将这些对象“翻译”成对应的 SQL 片段(字符串),并收集参数值。最终拼接成完整的、可执行的 SQL 语句。

总结 SQL Provider 原理: 利用 MyBatis 的 Provider 机制,将结构化的 QueryWrapper 对象传递给一个专门的 SqlProvider 类。SqlProvider 调用 QueryWrapper 的 toSQL() 方法,该方法利用 APT 生成的元数据 (TableDef 和 QueryColumn) 将查询意图动态地、安全地(类型安全、字段名正确)翻译成 SQL 字符串和参数列表。这个过程完全在运行时由 Java 代码完成,不依赖 XML。

五. 小结:MyBatis-Flex 香在哪?

  • 开发效率爆炸: Lambda 链式 Wrapper + APT 生成 + 无 XML,写代码行云流水,减少错误。

  • 代码可读性极强: Java 代码清晰表达查询意图,维护方便。

  • 性能优异: 精心设计的 SQL 生成逻辑,优化过的分页,避免 N+1。

  • 功能全面: CRUD、分页、关联、逻辑删、多租户、乐观锁,数据脱敏,字段加密,动态数据源,动态表,多数据源,读写分离. 开箱即用。

  • 拥抱新特性: 深度集成 Lambda 表达式和 APT,现代化开发体验。

  • 轻量灵活: 核心精简,易于集成和理解。

如果你受够了 XML 的繁琐,又觉得其他 ORM 的 Wrapper 不够优雅或性能有顾虑,MyBatis-Flex 绝对值得你一试!

 它让你用更愉悦的方式,写出更高效、更健壮的数据库访问代码。赶紧上手体验一下吧!🚀

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nextera-void

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值