在 MyBatis 项目里,实体类和数据库表结构通常由两套流程维护:开发者修改 Java 字段,再手工编写建表或变更 SQL。xbatis-ddl-auto 1.0.1 提供了另一种选择:复用 xbatis 已经解析好的实体元数据,根据 @Table、@TableId、@TableField、@ColumnDefinition 等注解生成并执行 DDL。
它试图提供接近 JPA ddl-auto=create/update 的开发体验,但不要求项目引入 JPA 或 Hibernate。对于已经使用 xbatis 的应用,这意味着实体映射和自动建表可以基于同一套元数据,减少重复声明。
为什么复用实体元数据很重要
自动建表工具最容易出现的问题,不是不会生成 CREATE TABLE,而是它对实体类的理解与 ORM 不一致。
例如,ORM 将 createdAt 映射到 created_at,DDL 工具却创建了 createdAt;或者 ORM 忽略了某个临时字段,DDL 工具仍然为它创建列。这样的偏差会让应用启动成功,却在第一次读写时失败。
xbatis-ddl-auto 的关键思路是复用 xbatis 的注解解析结果:
@Table确定实体对应的表。@TableId标识主键字段。@TableField描述普通字段及其列映射。@ColumnDefinition补充列类型、长度或数据库约束等定义。
因此,自动 DDL 不需要再维护一份独立的实体扫描规则。字段重命名、主键声明和列定义仍然集中在实体类中。
create 与 update 解决的是不同问题
接近 JPA ddl-auto 的体验,并不意味着所有环境都应该开启同一种策略。
create 更适合一次性测试库、集成测试和可随时重建的本地数据库。它的核心价值是快速得到与当前实体匹配的全新结构,但也通常意味着已有表或数据可能被重建。启用前必须确认具体版本的执行行为。
update 更适合保留现有结构并补充变化的开发环境。不过,“更新结构”并不等于“可以无风险地完成任意数据库迁移”。增加可空列相对直接,删除列、缩短字符串长度、修改字段类型、增加非空约束则可能导致数据丢失或启动失败。
生产环境还需要考虑:
- 多个应用实例是否会同时执行 DDL。
- 数据库账号是否应拥有
CREATE、ALTER或DROP权限。 - 大表执行
ALTER TABLE是否会持锁或阻塞业务请求。 - 自动推断的变更是否经过审计并具备回滚方案。
因此,更稳妥的边界是:在开发和测试环境使用自动 DDL 提高迭代速度,在生产环境使用 Flyway、Liquibase 或经过评审的 SQL 迁移脚本。
可以这样组织实体定义
下面是一个可改造的 xbatis 实体示例。注解包名和 @ColumnDefinition 的具体参数形式需要按照项目使用的 xbatis 版本补齐,但字段设计展示了自动 DDL 所需的核心元数据。
package com.example.account;
import java.time.LocalDateTime;
// 请由 IDE 根据项目中的 xbatis 版本补齐注解 import。
@Table("app_user")
public class UserEntity {
@TableId
private Long id;
@TableField("username")
@ColumnDefinition("varchar(64) not null")
private String username;
@TableField("email")
@ColumnDefinition("varchar(255) not null")
private String email;
@TableField("enabled")
@ColumnDefinition("boolean not null")
private Boolean enabled;
@TableField("created_at")
@ColumnDefinition("timestamp not null")
private LocalDateTime createdAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
}
这类实体大致表达了以下数据库结构,但实际 SQL 会受到数据库方言、主键策略和 xbatis-ddl-auto 解析规则影响:
CREATE TABLE app_user (
id BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
email VARCHAR(255) NOT NULL,
enabled BOOLEAN NOT NULL,
created_at TIMESTAMP NOT NULL,
PRIMARY KEY (id)
);
接入 1.0.1 时,应使用该版本文档提供的依赖坐标和配置项,不要直接套用其他 ORM 的 ddl-auto 配置键。一个合理的环境策略可以抽象为:
# 配置名称是接入模板,请替换成 xbatis-ddl-auto 1.0.1 的实际属性名。
ddl-auto:
enabled: true
mode: update
# 生产环境策略:关闭应用启动时自动修改表结构。
ddl-auto:
enabled: false
重点不在配置键长什么样,而在于通过环境配置明确控制 DDL 是否执行,避免把开发环境的自动建表行为直接带入生产。
启用前先做一次结构基线
即使只在测试环境使用 update,也建议在首次启用前导出结构。以 MySQL 为例,可以复制并修改下面的命令:
export DB_HOST=127.0.0.1
export DB_PORT=3306
export DB_NAME=demo
export DB_USER=demo_user
mysqldump \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password \
--no-data \
--routines \
--triggers \
"$DB_NAME" > schema-before-ddl-auto.sql
应用启动后,再导出一次结构并比较:
mysqldump \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password \
--no-data \
--routines \
--triggers \
"$DB_NAME" > schema-after-ddl-auto.sql
diff -u schema-before-ddl-auto.sql schema-after-ddl-auto.sql
这一步可以快速发现意外的列类型变化、默认值变化或表结构重建。若工具支持只生成 SQL、不立即执行,也应优先在 CI 中审查生成结果。
落地时检查这几件事
引入 xbatis-ddl-auto 1.0.1 前,可以按下面的清单控制风险:
- 确认所有实体都使用一致的
@Table和字段映射规则。 - 检查主键生成方式是否与目标数据库兼容。
- 为字符串长度、非空约束和默认值提供明确的列定义。
- 在空数据库上验证
create结果,并运行完整集成测试。 - 在带有真实结构副本的数据库上验证
update,检查生成的 DDL。 - 避免让多个应用实例在同一时间执行结构更新。
- 生产数据库使用低权限应用账号,并关闭启动时自动 DDL。
- 对删除列、字段改名和类型收窄继续使用显式迁移脚本。
xbatis-ddl-auto 的价值在于消除开发阶段重复维护表结构的机械工作,而不是替代所有数据库变更管理。把它用于可重建环境,并为生产变更保留审查、备份和回滚流程,才能同时获得开发效率与结构安全。