Boost Your Java Backend: Master MyBatis Generator for Automatic CRUD Code

This article explains how to integrate MyBatis Generator into a Spring Boot project, configure it to generate entity classes, mapper XML and CRUD methods, and extend its capabilities with custom comment generators, advanced queries, and one‑to‑many/one‑to‑one mappings, reducing manual coding effort.

macrozheng
macrozheng
macrozheng
Boost Your Java Backend: Master MyBatis Generator for Automatic CRUD Code

Introduction

MyBatis Generator (MBG) is an official MyBatis code generator that can create entity classes, single‑table CRUD code and mapper XML files directly from database tables, saving manual effort.

Getting Started

First we use a simple example to set up MBG with basic CRUD operations.

Integrate MBG

Add dependencies to pom.xml (MyBatis Spring Boot starter, PageHelper, Druid, MBG, MySQL driver).

<dependencies>
    <!--SpringBoot整合MyBatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.3</version>
    </dependency>
    <!--MyBatis分页插件-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.3.0</version>
    </dependency>
    <!--集成druid连接池-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <!-- MyBatis 生成器 -->
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    <!--Mysql数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.15</version>
    </dependency>
</dependencies>

Configure data source and MyBatis mapper locations in application.yml.

# 数据源配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root

# MyBatis mapper.xml路径配置
mybatis:
  mapper-locations:
    - classpath:dao/*.xml
    - classpath*:com/**/mapper/*.xml

Add Java configuration to scan mapper packages.

@Configuration
@MapperScan({"com.macro.mall.tiny.mbg.mapper","com.macro.mall.tiny.dao"})
public class MyBatisConfig {
}

Use the Generator

Configure database connection in generator.properties.

jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.userId=root
jdbc.password=root

Define generation rules in generatorConfig.xml (context, plugins, commentGenerator, jdbcConnection, model, mapper, client generators, table definitions, etc.).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <properties resource="generator.properties"/>
    <context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <property name="javaFileEncoding" value="UTF-8"/>
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
        <commentGenerator type="com.macro.mall.tiny.mbg.CommentGenerator">
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
            <property name="addRemarkComments" value="true"/>
        </commentGenerator>
        <jdbcConnection driverClass="${jdbc.driverClass}" connectionURL="${jdbc.connectionURL}" userId="${jdbc.userId}" password="${jdbc.password}">
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>
        <javaModelGenerator targetPackage="com.macro.mall.tiny.mbg.model" targetProject="mall-tiny-generator/src/main/java"/>
        <sqlMapGenerator targetPackage="com.macro.mall.tiny.mbg.mapper" targetProject="mall-tiny-generator/src/main/resources"/>
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.macro.mall.tiny.mbg.mapper" targetProject="mall-tiny-generator/src/main/java"/>
        <table tableName="ums_admin">
            <generatedKey column="id" sqlStatement="MySql" identity="true"/>
        </table>
        <!-- other tables -->
    </context>
</generatorConfiguration>

Optionally customize comment generation by extending DefaultCommentGenerator to add Swagger annotations.

package com.macro.mall.tiny.mbg;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
import java.util.Properties;

/**
 * Custom comment generator that adds @ApiModelProperty annotations.
 */
public class CommentGenerator extends DefaultCommentGenerator {
    private boolean addRemarkComments = false;
    private static final String EXAMPLE_SUFFIX = "Example";
    private static final String MAPPER_SUFFIX = "Mapper";
    private static final String API_MODEL_PROPERTY_FULL_CLASS_NAME = "io.swagger.annotations.ApiModelProperty";

    @Override
    public void addConfigurationProperties(Properties properties) {
        super.addConfigurationProperties(properties);
        this.addRemarkComments = StringUtility.isTrue(properties.getProperty("addRemarkComments"));
    }

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        String remarks = introspectedColumn.getRemarks();
        if (addRemarkComments && StringUtility.stringHasValue(remarks)) {
            if (remarks.contains("\"")) {
                remarks = remarks.replace("\"", "'");
            }
            field.addJavaDocLine("@ApiModelProperty(value = \"" + remarks + "\")");
        }
    }

    @Override
    public void addJavaFileComment(CompilationUnit compilationUnit) {
        super.addJavaFileComment(compilationUnit);
        String fullyQualifiedName = compilationUnit.getType().getFullyQualifiedName();
        if (!fullyQualifiedName.contains(MAPPER_SUFFIX) && !fullyQualifiedName.contains(EXAMPLE_SUFFIX)) {
            compilationUnit.addImportedType(new FullyQualifiedJavaType(API_MODEL_PROPERTY_FULL_CLASS_NAME));
        }
    }
}

Run the main Generator class to produce code.

/**
 * Generator for MBG code.
 */
public class Generator {
    public static void main(String[] args) throws Exception {
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;
        InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(is);
        is.close();
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
        for (String warning : warnings) {
            System.out.println(warning);
        }
    }
}

After execution, the generated code structure is displayed.

Basic CRUD Implementation

Using the generated mapper interfaces, basic CRUD methods are already available.
public interface UmsAdminMapper {
    long countByExample(UmsAdminExample example);
    int deleteByPrimaryKey(Long id);
    int insert(UmsAdmin record);
    int insertSelective(UmsAdmin record);
    List<UmsAdmin> selectByExample(UmsAdminExample example);
    UmsAdmin selectByPrimaryKey(Long id);
    int updateByExampleSelective(@Param("record") UmsAdmin record, @Param("example") UmsAdminExample example);
    int updateByPrimaryKeySelective(UmsAdmin record);
    int updateByPrimaryKey(UmsAdmin record);
}

Service implementation calls these methods for create, update, delete, select, and pagination.

@Service
public class UmsAdminServiceImpl implements UmsAdminService {
    @Autowired
    private UmsAdminMapper adminMapper;

    @Override
    public void create(UmsAdmin entity) {
        adminMapper.insert(entity);
    }

    @Override
    public void update(UmsAdmin entity) {
        adminMapper.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void delete(Long id) {
        adminMapper.deleteByPrimaryKey(id);
    }

    @Override
    public UmsAdmin select(Long id) {
        return adminMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<UmsAdmin> listAll(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return adminMapper.selectByExample(new UmsAdminExample());
    }
}

Advanced Usage

Beyond basic operations, MBG supports conditional queries, subqueries, group/join, conditional delete/update, and one‑to‑many/one‑to‑one mappings through custom DAO methods and XML.

Conditional Query

SELECT id, username, PASSWORD, icon, email, nick_name, note, create_time, login_time, STATUS
FROM ums_admin
WHERE ( username = 'macro' AND STATUS IN (0,1) )
ORDER BY create_time DESC;
UmsAdminExample example = new UmsAdminExample();
UmsAdminExample.Criteria criteria = example.createCriteria();
if (StrUtil.isNotEmpty(username)) {
    criteria.andUsernameEqualTo(username);
}
criteria.andStatusIn(statusList);
example.setOrderByClause("create_time desc");
List<UmsAdmin> list = adminMapper.selectByExample(example);

Subquery

Define a custom DAO method subList(Long roleId) and implement SQL in UmsAdminDao.xml.

SELECT *
FROM ums_admin
WHERE id IN (SELECT admin_id FROM ums_admin_role_relation WHERE role_id = #{roleId});

Group and Join

Define groupList() in DAO and map results to RoleStatDto via a resultType query.

SELECT ur.id AS roleId,
       ur.NAME AS roleName,
       count(ua.id) AS count
FROM ums_role ur
LEFT JOIN ums_admin_role_relation uarr ON ur.id = uarr.role_id
LEFT JOIN ums_admin ua ON uarr.admin_id = ua.id
GROUP BY ur.id;

Conditional Delete

UmsAdminExample example = new UmsAdminExample();
example.createCriteria().andUsernameEqualTo(username);
adminMapper.deleteByExample(example);

Conditional Update

UmsAdmin record = new UmsAdmin();
record.setStatus(status);
UmsAdminExample example = new UmsAdminExample();
example.createCriteria().andIdIn(ids);
adminMapper.updateByExampleSelective(record, example);

One‑to‑Many Query

Define selectWithRoleList(Long id) and use a resultMap with a collection element and columnPrefix="role_" to map roles.

One‑to‑One Query

Define selectResourceWithCate(Long id) and use a resultMap with an association element and columnPrefix="cate_" to map the category.

Conclusion

MyBatis Generator is powerful for generating common single‑table CRUD code, reducing manual work, but it has limited support for subqueries, multi‑table and complex queries, which still require hand‑written SQL in mapper XML.

References

Official documentation: https://mybatis.org/generator/index.html

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.

BackendJavaCode GenerationMyBatisCRUDMyBatis Generator
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.