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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
