Backend Development 9 min read

Implementing Student Score Statistics with Fluent MyBatis, MyBatis, and MyBatis‑Plus

This article demonstrates how to use Fluent MyBatis, native MyBatis, and MyBatis‑Plus to query a student_score table for term‑wise statistics of English, Math, and Chinese scores, providing complete code examples, SQL statements, mapper definitions, and code‑generation configurations for each approach.

Top Architect
Top Architect
Top Architect
Implementing Student Score Statistics with Fluent MyBatis, MyBatis, and MyBatis‑Plus

The author, a senior architect, introduces Fluent MyBatis, a Java API that enables building complex SQL without XML files, and compares it with native MyBatis and MyBatis‑Plus.

Database schema for the example 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;

The business requirement is to count, find the minimum, maximum, and average scores for the three subjects (English, Math, Chinese) in each term, only for records with a passing score (≥60) and with at least two samples.

Corresponding SQL statement:

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;

Fluent MyBatis implementation – using the fluent API to build the same query without XML. The author shows the generated code and IDE rendering, highlighting the concise expression.

Native MyBatis implementation – three steps are shown:

Define the mapper interface:

public interface MyStudentScoreMapper {
    List
> summaryScore(SummaryQuery paras);
}

Create the parameter class:

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

Write the XML mapping:

<select 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>

A test class demonstrates invoking the mapper:

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

MyBatis‑Plus implementation – the author shows a much shorter code snippet using the built‑in wrapper methods, but points out the heavy reliance on hard‑coded column strings.

Code generation settings for Fluent MyBatis:

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

Code generation settings for MyBatis‑Plus:

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

Finally, the author summarizes the three approaches, noting that Fluent MyBatis offers a balanced API with type safety, native MyBatis is verbose, and MyBatis‑Plus is concise but prone to string‑based errors, helping readers decide which tool fits their project.

Javacode generationSQLbackend developmentMyBatisMyBatis-PlusFluent MyBatis
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.