建好了表,还在手动写CRUD的xml?兄弟,真得学习MBG了!

还在手动写CRUD的XML?兄弟,真得学习MBG了!

兄弟,如果你还在为MyBatis手写一堆XML的CRUD操作累得焦头烂额,那真得停下来看看MyBatis Generator(简称MBG)了!它能帮你自动生成Model、Mapper接口和XML配置文件,极大提升开发效率。本文将基于Spring Boot 3 + MyBatis 3的技术栈,带你从建表SQL到MBG配置,再到项目结构和手动写DAO的场景,全面解析MBG的用法和注意事项。话不多说,直接上干货!


一、建表SQL:先把数据库结构搭好

我们以一个简单的电商场景为例,创建三张表:user(用户信息)、product(商品信息)和order(订单信息),并建立适当的外键关系。

sql 复制代码
-- 创建用户表
CREATE TABLE `user` (
  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `username` VARCHAR(50) NOT NULL COMMENT '用户名',
  `email` VARCHAR(100) NOT NULL COMMENT '邮箱',
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 创建商品表
CREATE TABLE `product` (
  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '商品ID',
  `name` VARCHAR(100) NOT NULL COMMENT '商品名称',
  `price` DECIMAL(10, 2) NOT NULL COMMENT '价格',
  `stock` INT NOT NULL COMMENT '库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';

-- 创建订单表
CREATE TABLE `order` (
  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '订单ID',
  `user_id` BIGINT NOT NULL COMMENT '用户ID',
  `product_id` BIGINT NOT NULL COMMENT '商品ID',
  `quantity` INT NOT NULL COMMENT '购买数量',
  `order_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '下单时间',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
  FOREIGN KEY (`product_id`) REFERENCES `product` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

这些表结构简单明了,包含了主键、外键和常见字段类型,适合展示MBG的生成效果。


二、项目结构:MBG生成什么,手动写什么?

在使用MBG之前,先来看看项目的目录结构,方便你理解哪些文件是MBG自动生成的,哪些需要我们手动补充。

bash 复制代码
project-root
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           ├── Application.java                # Spring Boot 启动类
│   │   │           ├── config
│   │   │           │   └── MyBatisConfig.java          # MyBatis 配置类
│   │   │           ├── dao
│   │   │           │   ├── UserMapper.java             # MBG自动生成
│   │   │           │   ├── ProductMapper.java          # MBG自动生成
│   │   │           │   ├── OrderMapper.java            # MBG自动生成
│   │   │           │   └── CustomOrderDao.java         # 手动编写的DAO
│   │   │           ├── model
│   │   │           │   ├── User.java                   # MBG自动生成
│   │   │           │   ├── UserExample.java            # MBG自动生成
│   │   │           │   ├── Product.java                # MBG自动生成
│   │   │           │   ├── ProductExample.java         # MBG自动生成
│   │   │           │   ├── Order.java                  # MBG自动生成
│   │   │           │   └── OrderExample.java           # MBG自动生成
│   │   │           ├── service
│   │   │           │   ├── UserService.java            # 手动编写
│   │   │           │   ├── ProductService.java         # 手动编写
│   │   │           │   └── OrderService.java           # 手动编写
│   │   │           └── controller
│   │   │               └── OrderController.java        # 手动编写
│   │   └── resources
│   │       ├── mapper
│   │       │   ├── UserMapper.xml                     # MBG自动生成
│   │       │   ├── ProductMapper.xml                  # MBG自动生成
│   │       │   └── OrderMapper.xml                    # MBG自动生成
│   │       ├── application.yml                        # Spring Boot 配置文件
│   │       └── generatorConfig.xml                    # MBG配置文件
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── ApplicationTests.java           # 测试类
├── pom.xml                                            # Maven配置文件
└── README.md

说明

  • MBG自动生成UserMapper.javaProductMapper.javaOrderMapper.java(Mapper接口),User.javaProduct.javaOrder.java(实体类),UserExample.javaProductExample.javaOrderExample.java(条件查询类),以及mapper目录下的XML文件。
  • 手动编写CustomOrderDao.java(自定义DAO,处理复杂业务逻辑)、Service层、Controller层,以及Spring Boot的配置文件和启动类。

三、MBG配置:让代码自动生成

MBG的核心是generatorConfig.xml,我们需要配置数据库连接、生成规则和输出路径。下面是一个详细的配置文件,带注释说明每个部分的作用。

xml 复制代码
<?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>
    <!-- 数据库驱动:指定MySQL驱动的JAR包路径(需提前放入项目目录) -->
    <classPathEntry location="mysql-connector-java-8.0.30.jar" />

    <!-- 数据库连接配置 -->
    <context id="MySQLTables" targetRuntime="MyBatis3">
        <!-- 数据库连接信息 -->
        <jdbcConnection
            driverClass="com.mysql.cj.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/mbg_demo?useSSL=false&amp;serverTimezone=UTC"
            userId="root"
            password="your_password" />

        <!-- Java模型生成配置 -->
        <javaModelGenerator targetPackage="com.example.model" targetProject="src/main/java">
            <!-- 是否在当前路径下生成子包 -->
            <property name="enableSubPackages" value="true" />
            <!-- 是否对模型添加构造函数 -->
            <property name="constructorBased" value="false" />
            <!-- 是否对列名进行trim操作 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- SQL映射文件(XML)生成配置 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!-- Mapper接口生成配置 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.dao" targetProject="src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!-- 指定表和生成规则 -->
        <table tableName="user" domainObjectName="User" enableCountByExample="true"
               enableUpdateByExample="true" enableDeleteByExample="true"
               enableSelectByExample="true" selectByExampleQueryId="true">
            <!-- 是否生成Example类 -->
            <generatedKey column="id" sqlStatement="MySQL" identity="true" />
        </table>
        <table tableName="product" domainObjectName="Product" enableCountByExample="true"
               enableUpdateByExample="true" enableDeleteByExample="true"
               enableSelectByExample="true" selectByExampleQueryId="true">
            <generatedKey column="id" sqlStatement="MySQL" identity="true" />
        </table>
        <table tableName="order" domainObjectName="Order" enableCountByExample="true"
               enableUpdateByExample="true" enableDeleteByExample="true"
               enableSelectByExample="true" selectByExampleQueryId="true">
            <generatedKey column="id" sqlStatement="MySQL" identity="true" />
        </table>
    </context>
</generatorConfiguration>

关键点

  1. 数据库驱动 :需要下载mysql-connector-java并指定路径,或者通过Maven依赖引入。
  2. 生成路径javaModelGeneratorsqlMapGeneratorjavaClientGenerator分别控制Model、XML和Mapper接口的输出位置。
  3. 表配置 :通过<table>标签指定要生成的表,generatedKey用于设置主键自增。
  4. Example支持enable*ByExample属性开启条件查询功能,生成Example类。

运行MBG的方式:

  • 命令行java -jar mybatis-generator-core-1.4.0.jar -configfile generatorConfig.xml -overwrite
  • Maven插件 :配置mybatis-generator-maven-plugin并运行mvn mybatis-generator:generate

四、Spring Boot配置:整合MyBatis

为了让Spring Boot正常使用MyBatis和MBG生成的代码,我们需要配置application.yml和MyBatis配置类。

1. application.yml

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mbg_demo?useSSL=false&serverTimezone=UTC
    username: root
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.model

说明

  • spring.datasource:配置数据库连接。
  • mybatis.mapper-locations:指定MBG生成的XML文件路径。
  • mybatis.type-aliases-package:指定Model类的包路径,简化XML中的类型引用。

2. MyBatisConfig.java

kotlin 复制代码
package com.example.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.dao")
public class MyBatisConfig {
    // 配置MyBatis的Mapper扫描路径
}

说明

  • @MapperScan注解自动扫描com.example.dao包下的Mapper接口,省去手动添加@Mapper注解的麻烦。

五、MBG的Example类:灵活查询的利器

MBG生成的Example类是条件查询的核心,用于动态构建SQL的WHERE条件。比如,查询某个用户的订单:

ini 复制代码
OrderExample example = new OrderExample();
example.createCriteria()
    .andUserIdEqualTo(1L)
    .andOrderTimeGreaterThan(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000));
List<Order> orders = orderMapper.selectByExample(example);

Example的用处

  1. 动态查询 :通过createCriteria()or()方法,可以灵活组合查询条件。
  2. 批量操作 :支持updateByExampledeleteByExample等批量操作。
  3. 分页支持 :结合RowBounds实现分页查询。

使用场景

  • 复杂条件查询(如多字段组合、模糊查询)。
  • 批量更新或删除(如更新某类用户的状态)。

六、MBG的缺陷和手动写DAO的场景

虽然MBG很强大,但它也有局限性,有些场景需要我们手动写DAO和XML。

MBG的缺陷

  1. 复杂SQL不支持:MBG只生成简单的CRUD,复杂的多表联查、子查询或存储过程需要手动实现。
  2. 业务逻辑耦合:MBG生成的代码是通用的,难以直接处理业务逻辑(如订单状态流转)。
  3. XML维护问题:如果表结构变更,MBG重新生成会覆盖自定义的XML内容(除非配置插件)。

什么时候需要手动写DAO?

  1. 多表关联查询 :比如查询订单详情,需关联userproduct表。
  2. 复杂业务逻辑:如订单创建时需要检查库存、更新用户积分等。
  3. 自定义SQL:如统计报表、复杂聚合查询。
  4. 性能优化:MBG生成的SQL可能不够高效,手动优化能减少查询开销。

示例:手动实现的CustomOrderDao

kotlin 复制代码
package com.example.dao;

import com.example.model.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface CustomOrderDao {
    @Select("SELECT o.*, u.username, p.name AS product_name " +
            "FROM `order` o " +
            "JOIN `user` u ON o.user_id = u.id " +
            "JOIN `product` p ON o.product_id = p.id " +
            "WHERE o.user_id = #{userId}")
    List<Order> selectOrderDetailsByUserId(Long userId);
}

对应的XML(可选)

如果不用注解,可以在resources/mapper/CustomOrderMapper.xml中定义:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.CustomOrderDao">
    <select id="selectOrderDetailsByUserId" resultType="com.example.model.Order">
        SELECT o.*, u.username, p.name AS product_name
        FROM `order` o
        JOIN `user` u ON o.user_id = u.id
        JOIN `product` p ON o.product_id = p.id
        WHERE o.user_id = #{userId}
    </select>
</mapper>

七、总结:MBG的正确打开方式

MBG是解放双手的神器,能自动生成80%的CRUD代码,但它不是万能的。简单单表操作交给MBG,复杂业务逻辑和多表查询还是得靠手动DAO。合理结合MBG的Example类和自定义DAO,能让你的代码既高效又灵活。

小建议

  • 配置好generatorConfig.xml,跑一把MBG,感受自动化的快感。
  • 对于复杂业务,写个Custom*Dao专门处理,别和MBG生成的代码混在一起。
  • 善用Example类,动态查询省心又省力。

兄弟,赶紧把MBG用起来,告别手写XML的苦日子吧!如果有啥问题,欢迎留言讨论~

相关推荐
努力的小郑23 分钟前
MySQL索引(三):字符串索引优化之前缀索引
后端·mysql·性能优化
IT_陈寒1 小时前
🔥3分钟掌握JavaScript性能优化:从V8引擎原理到5个实战提速技巧
前端·人工智能·后端
程序员清风1 小时前
贝壳一面:年轻代回收频率太高,如何定位?
java·后端·面试
考虑考虑2 小时前
Java实现字节转bcd编码
java·后端·java ee
AAA修煤气灶刘哥2 小时前
ES 聚合爽到飞起!从分桶到 Java 实操,再也不用翻烂文档
后端·elasticsearch·面试
爱读源码的大都督2 小时前
Java已死?别慌,看我如何用Java手写一个Qwen Code Agent,拯救Java
java·人工智能·后端
星辰大海的精灵3 小时前
SpringBoot与Quartz整合,实现订单自动取消功能
java·后端·算法
天天摸鱼的java工程师3 小时前
RestTemplate 如何优化连接池?—— 八年 Java 开发的踩坑与优化指南
java·后端
一乐小哥3 小时前
一口气同步10年豆瓣记录———豆瓣书影音同步 Notion分享 🚀
后端·python
LSTM973 小时前
如何使用C#实现Excel和CSV互转:基于Spire.XLS for .NET的专业指南
后端