Fluent MyBatis vs MyBatis vs MyBatis Plus: Which ORM Handles Complex Queries Best?

This article compares Fluent MyBatis, native MyBatis, and MyBatis Plus by implementing a student score aggregation query, showcasing code examples, generator settings, and a detailed feature matrix to help developers choose the most efficient ORM for complex SQL construction.

Programmer DD
Programmer DD
Programmer DD
Fluent MyBatis vs MyBatis vs MyBatis Plus: Which ORM Handles Complex Queries Best?

Fluent MyBatis enables building complex business SQL through a Java API without writing XML, merging code and SQL logic and eliminating the need to assemble queries in DAO classes.

Scenario Setup

We use a typical student score table:

create table `student_score`(
    id bigint auto_increment comment '主键ID' primary key,
    student_id bigint not null comment '学号',
    gender_man tinyint default 0 not null comment '性别, 0:女; 1:男',
    school_term int null comment '学期',
    subject varchar(30) null comment '学科',
    score int null comment '成绩',
    gmt_create datetime not null comment '记录创建时间',
    gmt_modified datetime not null comment '记录最后修改时间',
    is_deleted tinyint default 0 not null comment '逻辑删除标识'
) engine = InnoDB default charset=utf8;

Requirement: count passing scores (≥60) for the three subjects "English", "Math", "Chinese" from 2000 onward, compute the minimum, maximum and average scores per term and subject, ensure each group has more than one record, and sort the results by term and subject.

select school_term,
       subject,
       count(score) as count,
       min(score) as min_score,
       max(score) as max_score,
       avg(score) as avg_score
from student_score
where school_term >= 2000
  and subject in ('英语','数学','语文')
  and score >= 60
  and is_deleted = 0
group by school_term, subject
having count(score) > 1
order by school_term, subject;

Implementation Comparison

Fluent MyBatis Implementation

The Fluent API allows direct method chaining to construct the query, and IDE can render the fluent syntax for better readability.

Native MyBatis Implementation

Define a mapper interface:

public interface MyStudentScoreMapper {
    List<Map<String, Object>> summaryScore(SummaryQuery paras);
}

Parameter class:

@Data
@Accessors(chain = true)
public class SummaryQuery {
    private Integer schoolTerm;
    private List<String> subjects;
    private Integer score;
    private Integer minCount;
}

Mapper XML:

<select id="summaryScore" resultType="map" parameterType="cn.org.fluent.mybatis.springboot.demo.mapper.SummaryQuery">
    select school_term, subject,
           count(score) as count,
           min(score) as min_score,
           max(score) as max_score,
           avg(score) as avg_score
    from student_score
    where school_term >= #{schoolTerm}
      and subject in
      <foreach collection="subjects" item="item" open="(" close=")" separator=",">
          #{item}
      </foreach>
      and score >= #{score}
      and is_deleted = 0
    group by school_term, subject
    having count(score) > #{minCount}
    order by school_term, subject
</select>

Test class:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = QuickStartApplication.class)
public class MybatisDemo {
    @Autowired
    private MyStudentScoreMapper mapper;

    @Test
    public void mybatis_demo() {
        SummaryQuery paras = new SummaryQuery()
            .setSchoolTerm(2000)
            .setSubjects(Arrays.asList("英语", "数学", "语文"))
            .setScore(60)
            .setMinCount(1);
        List<Map<String, Object>> summary = mapper.summaryScore(paras);
        System.out.println(summary);
    }
}

MyBatis Plus Implementation

MyBatis Plus simplifies the code, but still relies on hard‑coded field names and string literals, which can increase the learning curve.

Code Generation Comparison

Fluent MyBatis Generator Settings

public class AppEntityGenerator {
    static final String url = "jdbc:mysql://localhost:3306/fluent_mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8";

    public static void main(String[] args) {
        FileGenerator.build(Abc.class);
    }

    @Tables(
        /** Database connection */
        url = url, username = "root", password = "password",
        /** Entity package */
        basePack = "cn.org.fluent.mybatis.springboot.demo",
        /** Source directories */
        srcDir = "spring-boot-demo/src/main/java",
        daoDir = "spring-boot-demo/src/main/java",
        /** Logical delete fields */
        gmtCreated = "gmt_create", gmtModified = "gmt_modified", logicDeleted = "is_deleted",
        /** Tables to generate */
        tables = @Table(value = {"student_score"})
    )
    static class Abc {}
}

MyBatis Plus Generator Settings

public class CodeGenerator {
    static String dbUrl = "jdbc:mysql://localhost:3306/fluent_mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8";

    @Test
    public void generateCode() {
        GlobalConfig config = new GlobalConfig();
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDbType(DbType.MYSQL)
            .setUrl(dbUrl)
            .setUsername("root")
            .setPassword("password")
            .setDriverName(Driver.class.getName());
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig
            .setCapitalMode(true)
            .setEntityLombokModel(false)
            .setNaming(NamingStrategy.underline_to_camel)
            .setColumnNaming(NamingStrategy.underline_to_camel)
            .setEntityTableFieldAnnotationEnable(true)
            .setFieldPrefix(new String[]{"test_"})
            .setInclude(new String[]{"student_score"})
            .setLogicDeleteFieldName("is_deleted")
            .setTableFillList(Arrays.asList(
                new TableFill("gmt_create", FieldFill.INSERT),
                new TableFill("gmt_modified", FieldFill.INSERT_UPDATE)));
        config
            .setActiveRecord(false)
            .setIdType(IdType.AUTO)
            .setOutputDir(System.getProperty("user.dir") + "/src/main/java/")
            .setFileOverride(true);
        new AutoGenerator()
            .setGlobalConfig(config)
            .setDataSource(dataSourceConfig)
            .setStrategy(strategyConfig)
            .setPackageInfo(new PackageConfig()
                .setParent("com.mp.demo")
                .setController("controller")
                .setEntity("entity"))
            .execute();
    }
}

Fluent MyBatis Feature Overview

Comparison Summary

Code Generation : MyBatis Plus generates only Entity classes, while Fluent MyBatis generates Entity, Mapper, Query, Update, and SqlProvider.

Generator Ease of Use : Fluent MyBatis scores high, MyBatis Plus low.

Integration with MyBatis : MyBatis Plus requires replacing the original SqlSessionFactoryBean; Fluent MyBatis works without any changes to existing MyBatis usage.

Dynamic SQL Construction : MyBatis Plus builds XML fragments at application startup; Fluent MyBatis compiles SQL providers at compile time.

Debugging Dynamic SQL : Fluent MyBatis allows setting breakpoints directly on generated provider methods, making debugging easier.

Field Name Changes Detection : Fluent MyBatis detects mismatches at compile time, whereas MyBatis Plus may only catch them at runtime when using string literals.

Syntax Rendering : Fluent MyBatis offers IDE‑friendly syntax highlighting via fluent keywords (select, update, set, and, or); MyBatis Plus provides none.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSQLMyBatisORMmybatis-plusFluent MyBatis
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.