1. 项目概述
在Java企业级开发中,MyBatis作为一款优秀的持久层框架,其核心优势在于将SQL与Java代码解耦。而mybatis-generator插件正是MyBatis官方提供的代码生成工具,能够根据数据库表结构自动生成实体类、Mapper接口和XML映射文件,大幅减少重复编码工作。本文将深入解析如何精准控制生成范围,仅针对指定数据表生成所需的三层结构代码。
实际开发中常遇到这样的场景:一个已有数百张表的生产数据库,我们只需要对其中的5-8张表进行功能迭代。此时全量生成显然不合理,而手动复制修改又容易出错。通过配置表的白名单机制,可以实现精准生成,避免覆盖已有业务逻辑。
2. 环境准备与插件配置
2.1 基础环境搭建
首先确保项目中已正确引入MyBatis依赖。对于Maven项目,在pom.xml中添加如下配置:
xml复制<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
注意:建议使用1.4.0及以上版本,该版本对Java8+有更好的支持,且修复了早期版本中的多个类型处理bug。
2.2 生成器配置文件详解
在resources目录下创建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>
<!-- 数据库驱动配置 -->
<context id="mysqlTables" targetRuntime="MyBatis3">
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/your_db"
userId="root"
password="123456">
</jdbcConnection>
<!-- 实体类生成位置 -->
<javaModelGenerator targetPackage="com.example.entity"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- XML映射文件生成位置 -->
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- DAO接口生成位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.dao"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 指定表配置 -->
<table tableName="user_info" domainObjectName="User"/>
<table tableName="order_detail" domainObjectName="Order"/>
</context>
</generatorConfiguration>
关键配置项说明:
tableName:数据库中的实际表名domainObjectName:生成的实体类名(可自定义)enableSubPackages:是否允许创建子包trimStrings:自动对String类型字段做trim处理
3. 高级配置技巧
3.1 字段级自定义控制
有时需要对特定字段进行特殊处理,比如:
- 忽略某些字段不生成
- 修改字段的Java类型
- 添加自定义注释
配置示例:
xml复制<table tableName="product" domainObjectName="Product">
<columnOverride column="price" javaType="java.math.BigDecimal" />
<ignoreColumn column="deleted_flag" />
<columnOverride column="create_time">
<property name="remarks" value="创建时间(UTC格式)"/>
</columnOverride>
</table>
3.2 生成规则定制
通过修改targetRuntime属性可以改变生成风格:
MyBatis3:默认风格MyBatis3Simple:不生成Example类MyBatis3DynamicSql:使用动态SQL
对于新项目推荐使用DynamicSql模式:
xml复制<context id="mysqlTables" targetRuntime="MyBatis3DynamicSql">
3.3 类型处理器配置
处理特殊数据类型转换,如枚举类型:
xml复制<table tableName="order_status">
<columnOverride column="status"
javaType="com.example.enums.OrderStatusEnum"
typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
</table>
4. 执行生成与集成
4.1 命令行执行方式
通过Maven插件执行生成:
xml复制<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
执行命令:
bash复制mvn mybatis-generator:generate
4.2 程序化调用方式
更灵活的方式是通过Java代码控制:
java复制public class Generator {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<>();
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(true);
MyBatisGenerator generator = new MyBatisGenerator(config, callback, warnings);
generator.generate(null);
warnings.forEach(System.out::println);
}
}
5. 生成结果优化
5.1 实体类增强
生成的实体类通常比较基础,可以:
- 添加Lombok注解减少样板代码
java复制@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String username;
// ...
}
- 实现Serializable接口
- 添加字段校验注解
java复制public class User {
@NotBlank(message = "用户名不能为空")
@Size(max = 32, message = "用户名长度不能超过32")
private String username;
}
5.2 XML文件优化
- 启用二级缓存:
xml复制<mapper namespace="com.example.dao.UserMapper">
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
</mapper>
- 添加自定义SQL片段:
xml复制<sql id="Base_Column_List">
id, username, email
</sql>
<select id="selectById" resultMap="BaseResultMap">
select <include refid="Base_Column_List"/>
from user_info
where id = #{id}
</select>
6. 常见问题排查
6.1 生成文件被覆盖问题
现象:已有自定义方法被生成器覆盖
解决方案:
- 使用merge模式:
xml复制<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.dao"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="mergeable" value="true"/>
</javaClientGenerator>
- 将自定义方法写在单独的扩展接口中:
java复制public interface UserMapperExt {
List<User> selectByCustomCondition(Condition condition);
}
public interface UserMapper extends BaseMapper<User>, UserMapperExt {
}
6.2 复杂类型处理
处理JSON字段的典型方案:
- 自定义类型处理器:
java复制public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
private Class<T> type;
public JsonTypeHandler(Class<T> type) {
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
T parameter, JdbcType jdbcType) {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public T getNullableResult(ResultSet rs, String columnName) {
return JSON.parseObject(rs.getString(columnName), type);
}
// 其他重载方法...
}
- 在配置中指定:
xml复制<columnOverride column="attributes"
javaType="com.example.model.ProductAttributes"
typeHandler="com.example.handler.JsonTypeHandler"/>
6.3 多表关联查询
虽然generator不直接生成关联查询,但可以通过以下方式扩展:
- 手动编写ResultMap:
xml复制<resultMap id="OrderWithUserResultMap" type="Order" extends="BaseResultMap">
<association property="user" javaType="User">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
</association>
</resultMap>
- 使用注解方式:
java复制public interface OrderMapper {
@Select("SELECT o.*, u.username FROM order_detail o JOIN user_info u ON o.user_id = u.id")
@ResultMap("OrderWithUserResultMap")
List<Order> selectOrdersWithUser();
}
7. 工程化实践建议
7.1 多环境配置管理
通过Maven Profile实现不同环境配置切换:
xml复制<profiles>
<profile>
<id>dev</id>
<properties>
<jdbc.url>jdbc:mysql://dev-db:3306/app</jdbc.url>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<jdbc.url>jdbc:mysql://prod-db:3306/app</jdbc.url>
</properties>
</profile>
</profiles>
在generatorConfig.xml中引用:
xml复制<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="${jdbc.url}"
userId="${jdbc.user}"
password="${jdbc.pass}">
</jdbcConnection>
7.2 增量生成策略
建议采用以下目录结构:
code复制src/
├── main/
│ ├── java/
│ │ ├── com.example.dao/ # 生成的接口
│ │ ├── com.example.dao.ext/ # 自定义扩展接口
│ │ └── com.example.entity/ # 实体类
│ └── resources/
│ ├── mapper/ # 生成的XML
│ └── mapper.ext/ # 自定义XML
7.3 生成代码质量检查
集成Checkstyle规范验证:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<includeTestSourceDirectory>false</includeTestSourceDirectory>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
8. 进阶扩展方向
8.1 自定义插件开发
继承PluginAdapter实现自定义逻辑:
java复制public class CustomCommentPlugin extends PluginAdapter {
@Override
public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass,
IntrospectedColumn column,
IntrospectedTable table,
ModelClassType modelClassType) {
field.addJavaDocLine("/**");
field.addJavaDocLine(" * " + column.getRemarks());
field.addJavaDocLine(" */");
return true;
}
}
在配置中启用:
xml复制<plugin type="com.example.plugin.CustomCommentPlugin"/>
8.2 与MyBatis-Plus集成
虽然generator生成的是原生MyBatis代码,但可以适配MyBatis-Plus:
- 让Mapper接口继承BaseMapper:
java复制public interface UserMapper extends BaseMapper<User> {
// 自定义方法...
}
- 修改生成模板,添加@Repository注解:
xml复制<context id="mysqlTables" targetRuntime="MyBatis3">
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<plugin type="org.mybatis.generator.plugins.RepositoryPlugin"/>
</context>
8.3 多模块项目支持
对于大型项目,建议按功能拆分模块:
code复制project/
├── domain/ # 实体类模块
├── persistence/ # Mapper接口和XML
└── service/ # 业务逻辑层
配置时需要指定跨模块的targetProject路径:
xml复制<javaModelGenerator targetPackage="com.example.entity"
targetProject="../domain/src/main/java"/>
9. 性能优化建议
9.1 生成过程加速
- 使用内存数据库缓存表结构:
xml复制<jdbcConnection
driverClass="org.h2.Driver"
connectionURL="jdbc:h2:mem:temp;DB_CLOSE_DELAY=-1"
userId="sa"
password="">
<property name="useInformationSchema" value="true"/>
</jdbcConnection>
- 并行生成多个表:
java复制Configuration config = ...;
ExecutorService executor = Executors.newFixedThreadPool(4);
config.getContexts().forEach(ctx ->
executor.submit(() ->
new MyBatisGenerator(ctx.getConfiguration(), ...).generate(null))
);
9.2 生成结果优化
- 启用延迟加载:
xml复制<context id="mysqlTables" targetRuntime="MyBatis3">
<property name="lazyLoadingEnabled" value="true"/>
<property name="aggressiveLazyLoading" value="false"/>
</context>
- 批量操作方法生成:
xml复制<table tableName="user">
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
<selectKey keyProperty="id" resultType="long" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
</table>
10. 最佳实践总结
经过多个项目的实践验证,以下配置组合效果最佳:
- 使用MyBatis3DynamicSql作为targetRuntime
- 启用mergeable防止覆盖自定义代码
- 集成Lombok减少样板代码
- 为关键字段添加校验注解
- 实现分模块代码生成
- 建立统一的代码风格检查机制
典型的企业级配置示例:
xml复制<context id="enterpriseConfig" targetRuntime="MyBatis3DynamicSql">
<property name="javaFileEncoding" value="UTF-8"/>
<property name="useActualColumnNames" value="false"/>
<property name="trimStrings" value="true"/>
<!-- 通用插件 -->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<plugin type="org.mybatis.generator.plugins.LombokPlugin">
<property name="hasBuilder" value="true"/>
</plugin>
<!-- 表配置 -->
<table tableName="%">
<property name="useActualColumnNames" value="false"/>
<generatedKey column="id" sqlStatement="MySql" identity="true"/>
</table>
</context>
在实际开发中,建议将生成器配置纳入版本控制,与项目一起演进。当数据库表结构变更时,可以快速重新生成基础代码,然后只修改受影响的自定义部分,保持开发效率的同时确保代码质量。
