Backend Development 16 min read

Fluent Mybatis Tutorial: Introduction, Features, Comparison with MyBatis/MyBatis Plus, and Practical CRUD Implementation

This article introduces the Fluent Mybatis ORM framework, explains its design advantages, demonstrates how to implement a complex student‑score aggregation query using Fluent Mybatis, native MyBatis and MyBatis‑Plus, and provides end‑to‑end code examples for entity generation, configuration, and CRUD testing.

Architecture Digest
Architecture Digest
Architecture Digest
Fluent Mybatis Tutorial: Introduction, Features, Comparison with MyBatis/MyBatis Plus, and Practical CRUD Implementation

The article introduces Fluent Mybatis , a MyBatis‑enhancing ORM that integrates features from MyBatis‑Plus, Dynamic SQL and JPA, and generates code via an annotation processor, allowing developers to write complex SQL with a fluent Java API without XML mapping files.

Key highlights include the ability to construct sophisticated business queries directly in Java, unifying code and SQL logic, and eliminating the need for manual XML or mapper interfaces.

As a concrete example, the author defines a requirement to aggregate student scores for three subjects (English, Math, Chinese) after the year 2000, calculating count, minimum, maximum and average scores, filtering groups with more than one record, and ordering by term and subject. The raw SQL is shown:

select school_term,
       subject,
       count(score) as count,
       min(score)   as min_score,
       max(score)   as max_score,
       avg(score)   as max_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;

The article then demonstrates three ways to implement this requirement.

1. Using Fluent Mybatis – the author shows the fluent API (illustrated with an image) that builds the same query programmatically, highlighting IDE auto‑completion and type safety.

2. Using native Mybatis – the full implementation is provided, including a mapper interface, a parameter POJO, the corresponding XML, and a JUnit test class:

public interface MyStudentScoreMapper {
    List
> summaryScore(SummaryQuery paras);
}
@Data
@Accessors(chain = true)
public class SummaryQuery {
    private Integer schoolTerm;
    private List
subjects;
    private Integer score;
    private Integer minCount;
}
<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 max_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>
@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
> summary = mapper.summaryScore(paras);
        System.out.println(summary);
    }
}

3. Using MyBatis‑Plus – a shorter implementation is shown, but the author points out heavy reliance on hard‑coded string literals, which can increase maintenance difficulty.

The article also covers code generation with Fluent Mybatis. Two generator examples are provided:

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(
        url = url, username = "root", password = "password",
        basePack = "cn.org.fluent.Mybatis.springboot.demo",
        srcDir = "spring-boot-demo/src/main/java",
        daoDir = "spring-boot-demo/src/main/java",
        gmtCreated = "gmt_create", gmtModified = "gmt_modified", logicDeleted = "is_deleted",
        tables = @Table(value = {"student_score"})
    )
    static class Abc {}
}
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();
    }
}

A hands‑on "Hello World" example is then presented. The steps include adding Maven dependencies:

<dependencies>
    <dependency>
        <groupId>com.github.atool</groupId>
        <artifactId>fluent-mybatis</artifactId>
        <version>1.9.3</version>
    </dependency>
    <dependency>
        <groupId>com.github.atool</groupId>
        <artifactId>fluent-mybatis-processor</artifactId>
        <version>1.9.3</version>
    </dependency>
</dependencies>

SQL to create the demo table:

create schema fluent_mybatis;
create table hello_world (
    id bigint unsigned auto_increment primary key,
    say_hello varchar(100) null,
    your_name varchar(100) null,
    gmt_created datetime DEFAULT NULL COMMENT '创建时间',
    gmt_modified datetime DEFAULT NULL COMMENT '更新时间',
    is_deleted tinyint(2) DEFAULT 0 COMMENT '是否逻辑删除'
) ENGINE = InnoDB CHARACTER SET utf8 COMMENT '简单演示表';

The corresponding entity class annotated with @FluentMybatis is shown:

@FluentMybatis
public class HelloWorldEntity extends RichEntity {
    private Long id;
    private String sayHello;
    private String yourName;
    private Date gmtCreated;
    private Date gmtModified;
    private Boolean isDeleted;
    // getters, setters, toString ...
    @Override
    public Class
entityClass() {
        return HelloWorldEntity.class;
    }
}

Spring configuration for DataSource and SqlSessionFactoryBean is provided:

@ComponentScan(basePackages = "cn.org.atool.fluent.mybatis.demo1")
@MapperScan("cn.org.atool.fluent.mybatis.demo1.entity.mapper")
@Configuration
public class HelloWorldConfig {
    @Bean
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/fluent_mybatis?useUnicode=true&characterEncoding=utf8");
        ds.setUsername("root");
        ds.setPassword("password");
        return ds;
    }
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean;
    }
    @Bean
    public MapperFactory mapperFactory() {
        return new MapperFactory();
    }
}

A JUnit test demonstrates CRUD operations using the generated HelloWorldMapper :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = HelloWorldConfig.class)
public class HelloWorldTest {
    @Autowired
    HelloWorldMapper mapper;

    @Test
    public void testHelloWorld() {
        // delete previous data
        mapper.delete(mapper.query().where.id().eq(1L).end());
        // insert
        HelloWorldEntity entity = new HelloWorldEntity();
        entity.setId(1L);
        entity.setSayHello("hello world");
        entity.setYourName("Fluent Mybatis");
        entity.setIsDeleted(false);
        mapper.insert(entity);
        // query
        HelloWorldEntity result1 = mapper.findOne(mapper.query().where.id().eq(1L).end());
        System.out.println("1. HelloWorldEntity:" + result1);
        // update
        mapper.updateBy(mapper.updater()
                .set.sayHello().is("say hello, say hello!")
                .set.yourName().is("Fluent Mybatis is powerful!")
                .where.id().eq(1L).end());
        // query after update
        HelloWorldEntity result2 = mapper.findOne(mapper.query()
                .where.sayHello().like("hello")
                .and.isDeleted().eq(false).end()
                .limit(1));
        System.out.println("2. HelloWorldEntity:" + result2);
    }
}

The article explains that Fluent Mybatis generates a set of helper classes at compile time, such as mapper interfaces, DAO base classes, query and updater wrappers, mapping helpers, and relation utilities, enabling developers to work without writing XML or manual DAO code.

In conclusion, Fluent Mybatis offers a concise, type‑safe way to perform CRUD and complex queries, reduces boilerplate compared to MyBatis and MyBatis‑Plus, and now also provides a form‑level CRUD solution. The article finishes with a promotional note offering a free book on a student‑management system for readers who reply with the keyword "图书".

Javacode generationDatabaseMyBatisORMFluent MyBatis
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login 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.