Why Fluent MyBatis Outshines MyBatis Plus and JOOQ for Java SQL Building

This article examines the evolution of Java SQL‑mapping frameworks, compares MyBatis, MyBatis Plus, MyBatis Dynamic SQL, JOOQ and the newer Fluent MyBatis, highlights Fluent MyBatis’s code‑centric design, IDE support, dynamic table naming, and provides practical code examples to illustrate its advantages.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
Why Fluent MyBatis Outshines MyBatis Plus and JOOQ for Java SQL Building

Popularity of MyBatis in East Asia

Google Trends shows that MyBatis dominates the Java SQL‑mapping market in East Asia and remains the most popular Java database access framework in China.

From iBatis to Modern Code‑First Solutions

iBatis, created in 2002, relied heavily on XML configuration. Over the years, the community shifted toward code‑first approaches, with MyBatis introducing annotation‑based SQL in 2010 and MyBatis Dynamic SQL embracing full code‑based query construction in 2016.

Emergence of Fluent MyBatis

Fluent MyBatis, launched at the end of 2019 by Alibaba’s technology team, combines the lightweight nature of MyBatis Dynamic SQL with richer features such as automatic code generation, compile‑time enhancements, and seamless IDE assistance.

Implementation Comparison

Fluent MyBatis adopts a mechanism similar to MyBatis Dynamic SQL, using native Provider annotations while generating additional helper classes during compilation. It hides internal details, offering a clean API for developers.

Fluent MyBatis Query Example

// Using Fluent MyBatis to build a query
mapper.listMaps(new StudentScoreQuery()
    .select
    .schoolTerm()
    .subject()
    .count.score("count")
    .min.score("min_score")
    .max.score("max_score")
    .avg.score("avg_score")
    .end()
    .where.schoolTerm().ge(2000)
    .and.subject.in(new String[]{"英语", "数学", "语文"})
    .and.score().ge(60)
    .and.isDeleted().isFalse()
    .end()
    .groupBy.schoolTerm().subject().end()
    .having.count.score.gt(1).end()
    .orderBy.schoolTerm().asc().subject().asc().end()
);

MyBatis Dynamic SQL Example

// Using MyBatis Dynamic SQL to build a query
mapper.selectMany(
    select(
        schoolTerm,
        subject,
        count(score).as("count"),
        min(score).as("min_score"),
        max(score).as("max_score"),
        avg(score).as("avg_score")
    ).from(studentScore)
    .where(schoolTerm, isGreaterThanOrEqualTo(2000))
    .and(subject, isIn("英语", "数学", "语文"))
    .and(score, isGreaterThanOrEqualTo(60))
    .and(isDeleted, isEqualTo(false))
    .groupBy(schoolTerm, subject)
    .having(count(score), isGreaterThan(1)) // currently not supported
    .orderBy(schoolTerm, subject)
    .build(isDeleted, isEqualTo(false))
    .render(RenderingStrategies.MYBATIS3)
);

JOOQ Example

// Using JOOQ to build a query
dslContext.select(
    STUDENT_SCORE.GENDER_MAN,
    STUDENT_SCORE.SCHOOL_TERM,
    STUDENT_SCORE.SUBJECT,
    count(STUDENT_SCORE.SCORE).as("count"),
    min(STUDENT_SCORE.SCORE).as("min_score"),
    max(STUDENT_SCORE.SCORE).as("max_score"),
    avg(STUDENT_SCORE.SCORE).as("avg_score")
)
.from(STUDENT_SCORE)
.where(
    STUDENT_SCORE.SCHOOL_TERM.ge(2000),
    STUDENT_SCORE.SUBJECT.in("英语", "数学", "语文"),
    STUDENT_SCORE.SCORE.ge(60),
    STUDENT_SCORE.IS_DELETED.eq(false)
)
.groupBy(STUDENT_SCORE.GENDER_MAN, STUDENT_SCORE.SCHOOL_TERM, STUDENT_SCORE.SUBJECT)
.having(count().gt(1))
.orderBy(STUDENT_SCORE.SCHOOL_TERM.asc(), STUDENT_SCORE.SUBJECT.asc())
.fetch();

Fluent MyBatis Update Example

// Updating only non‑null fields with Fluent MyBatis
new StudentUpdate()
    .update.name().is(student.getName(), If::notBlank)
    .set.phone().is(student.getPhone(), If::notBlank)
    .set.email().is(student.getEmail(), If::notBlank)
    .set.gender().is(student.getGender(), If::notNull)
    .end()
    .where.id().eq(student.getId()).end();

Generated Code Structure

Fluent MyBatis consists of two sub‑projects: Fluent Generator, which reads database metadata and generates Entity and DAO classes, and Fluent MyBatis, which provides a functional DSL for building SQL. The generated DAO extends a base DAO, while the processor module creates helper classes similar to Lombok’s annotation processing.

Workflow Overview

A typical workflow creates a Query or Update object, passes it to a Mapper, and the Mapper’s Provider methods assemble the final SQL using MyBatis’s existing execution engine, preserving features such as connection pooling and SQL injection protection.

Conclusion

Fluent MyBatis offers a modern, code‑centric alternative to XML‑heavy MyBatis configurations, delivering better readability, IDE assistance, dynamic table naming, and comprehensive SQL support, making it a compelling choice for Java backend developers.

Code GenerationMyBatisFluent MyBatisSQL BuilderJava ORM
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.