Master Fluent Mybatis: A Deep Dive into Java ORM Framework

This article introduces Fluent Mybatis, a Java ORM framework that enhances Mybatis with features from Mybatis Plus and JPA, demonstrates its core concepts, compares it with native Mybatis and Mybatis Plus through a student score query example, and provides step‑by‑step setup, code generation, and CRUD usage.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Master Fluent Mybatis: A Deep Dive into Java ORM Framework

Fluent Mybatis Introduction

Fluent Mybatis is a Mybatis‑enhancement framework that integrates the advantages of Mybatis Plus, Dynamic SQL, and JPA. It uses an annotation processor to generate code, allowing developers to write complex business SQL with a fluent Java API instead of XML.

Key Highlights

No XML files are required; SQL is built through Java code.

Code and SQL logic are unified, reducing the need for separate DAO assembly.

Annotation‑processor generates boilerplate mapper and entity code automatically.

Project address: https://gitee.com/fluent-mybatis/fluent-mybatis/wikis

Disclaimer: This framework is maintained personally. Use it only after thorough evaluation; it may not be suitable for production projects.

Core Concepts and Features

Fluent Mybatis combines Mybatis Plus, Dynamic SQL, and JPA features, generating code via annotation processing.

Feature Overview

Underlying Principle

Fluent Mybatis vs Mybatis vs Mybatis Plus

To illustrate differences, we implement a typical business requirement: calculate the minimum, maximum, and average scores for three subjects (English, Math, Chinese) per term, with at least two records per group.

Database Schema

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;

SQL Query

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 with Fluent Mybatis

Fluent Mybatis can express the same query using a fluent API without writing XML:

// Example code omitted for brevity – the fluent API builds the query and executes it directly.

Implementation with Native Mybatis

Requires a Mapper interface, a parameter POJO, and an XML mapper file:

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

public class SummaryQuery {
    private Integer schoolTerm;
    private List<String> 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 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>

Implementation with Mybatis Plus

Mybatis Plus simplifies the code but still relies on string literals for column names, which can cause maintenance issues:

// Example Mybatis Plus service code (omitted for brevity)

Comparison Summary

Fluent Mybatis eliminates XML and reduces boilerplate.

Mybatis Plus still requires hard‑coded column strings, leading to memorization and runtime errors when schema changes.

Native Mybatis is the most verbose and error‑prone.

Code Generation

Fluent Mybatis Code Generator

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 {}
}

Mybatis Plus Code Generator

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();
    }
}

Generated Files Overview

Fluent Mybatis generates the following components for each entity:

mapper/*Mapper – Mybatis mapper interface with generic CRUD methods.

dao/*BaseDao – Base DAO implementation.

wrapper/*Query – Dynamic query builder.

wrapper/*Updater – Dynamic update builder.

helper/*Mapping – Field‑to‑property mapping definitions.

helper/*Segment – Implementations for select, where, group‑by, having, order‑by, limit.

IEntityRelation – Interface for handling entity relationships.

Ref – Shortcut utility for accessing generated objects.

Practical Example: HelloWorld Entity

Table Definition

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 comment='简单演示表';

Entity Class

@FluentMybatis
public class HelloWorldEntity extends RichEntity {
    private Long id;
    private String sayHello;
    private String yourName;
    private Date gmtCreated;
    private Date gmtModified;
    private Boolean isDeleted;
    @Override
    public Class<? extends IEntity> entityClass() {
        return HelloWorldEntity.class;
    }
}

Configuration

@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();
    }
}

Test Case

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = HelloWorldConfig.class)
public class HelloWorldTest {
    @Autowired
    HelloWorldMapper mapper;
    @Test
    public void testHelloWorld() {
        // Delete any existing record with id=1
        mapper.delete(mapper.query().where.id().eq(1L).end());
        // Insert a new record
        HelloWorldEntity entity = new HelloWorldEntity();
        entity.setId(1L);
        entity.setSayHello("hello world");
        entity.setYourName("Fluent Mybatis");
        entity.setIsDeleted(false);
        mapper.insert(entity);
        // Query the inserted record
        HelloWorldEntity result1 = mapper.findOne(mapper.query().where.id().eq(1L).end());
        System.out.println("1. HelloWorldEntity:" + result1);
        // Update the record
        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);
    }
}

Running the test prints the entity before and after the update, confirming that Fluent Mybatis provides full CRUD capabilities with minimal boilerplate.

Conclusion

Fluent Mybatis offers a concise, annotation‑driven approach to Mybatis development, eliminating XML configuration and reducing repetitive code. By generating mappers, DAOs, and query/updater builders at compile time, it streamlines CRUD operations while keeping the flexibility of native Mybatis.

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.

SQLBackend DevelopmentFluent MyBatisJava ORM
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.