IntelliJ IDEA 2025.1 Help

逆向工程

逆向工程是基于数据库模式搭建 JPA 实体类的过程。

从数据库生成 JPA 实体

  1. 如果未建立数据库连接, 创建一个

  2. 数据库 工具窗口中,展开 JPA 节点,右键点击数据库或特定表,然后选择 新建 | 从数据库中获取 JPA 实体

  3. 从数据库创建 JPA 实体
  4. 选择一个数据库连接、表和属性进行映射。 有关更多信息,请参见 来自 DB Wizard 的实体

当您的 IDE 处于打开状态时,数据库可能会被其他客户端修改。 要从数据库中获取最新数据,您可以点击 ,无论是在 从数据库生成实体 窗口还是在 数据库 工具窗口。

来自 DB Wizard 的实体

数据库窗口中的实体

配置

窗口顶部的菜单允许您配置:

  • 数据库连接

  • 生成实体将保存的源根目录和包

  • 是否需要迁移索引和约束

  • 是否应在 @Table 注解中指定 schema 名称

此外,您还可以从 其他设置 下拉列表中,转到 实体声明逆向工程 设置。

映射关系、表和视图

在窗口的左侧,您可以看到:

  • 映射关系:映射到 JPA 实体的表和视图

  • 数据库中存在但未映射到实体的表

  • 视图:数据库中存在但未映射到实体的视图

选择树中的任意元素后,将出现一个用于从列迁移属性的面板。 此外,您将能够在相应字段中定义 class name。

迁移属性

窗口的主要部分允许您配置与属性相关的所有内容。 您可以选择要添加的属性,并更改它们的所有参数, 列名 除外。 映射类型和属性 / 转换器 / hibernate 类型表示为下拉列表。

所有属性分为 3 类:

  • 已迁移列——已存在于实体中的列(仅适用于映射关系)

  • 列 - 尚未在实体或父 @MappedSuperclass 中映射的新列

  • 引用——在观察到的表格中未表示为列的可选关联

父实体

IntelliJ IDEA 提供通过从 @MappedSuperclass 注释的类中选择一个类以定义父实体的功能,这可以在 父项 下拉框中完成。 这允许生成的实体扩展自父类,并自动继承所有具有相同名称和类型的属性。

@MappedSuperclass 中的列名与子实体的表不匹配的情况下,我们仍然可以使用 @AttributeOverride 注解继承该属性。 通过简单地选择属性名称并选择要覆盖的属性,IntelliJ IDEA 可以帮助管理继承。

attribute-override.png

在生成实体期间,IntelliJ IDEA 如果检测到数据库中缺少来自 @MappedSuperclass 的任何继承属性,会发出警报。 要使模型与数据库对齐,请访问 JPA Structure 菜单中的 通过实体生成 DDL 操作并选择 现有数据库更新 选项。

创建枚举

对于匹配 StringInteger 类型的属性,您可以将映射类型从 Basic 更改为 Enum,然后 IntelliJ IDEA 会在项目中创建相应的 Enum 类。 您需要手动填充 enum 的适当值。

处理未知类型

对于某些 SQL 类型,没有与 Java 类完全匹配的对应关系。 在这种情况下,IntelliJ IDEA 不设置类型,以防止生成无效的代码。 您需要自己选择属性类型。 您还可以在 设置中为每个 DBMS 配置默认类型映射。

如果您的项目依赖列表中有 HibernateTypes 库,IntelliJ IDEA 在逆向工程过程中可以自动为不支持的 SQL 类型建议适合的库类型:

// TODO 注释

如果您想推迟特定列的属性创建,您可以选择 //todo comment 作为映射类型。 IntelliJ IDEA 会根据列类型生成 //todo 注释及相应的快速修复操作。 您可以按 Ctrl+B 执行这些操作:

  • 对于已知的基本和关联类型,您可以:

    • 按原样取消注释

    • 移除列映射

  • 对于未知的 column 类型,您可以:

    • 定义目标 Java 类型

    • 按原样取消注释

    • 移除列映射

这里是为具有未知列类型的属性生成的 //todo 注释示例:

/* TODO [Reverse Engineering] create field to map the 'description' column Available actions: Define target Java type | Uncomment as is | Remove column mapping @Column(name = "description", columnDefinition = "jsonb") private java.lang.Object description; */

调用 定义目标 Java 类型 操作后,将出现以下窗口:

mapping-java-type

IntelliJ IDEA 将记住数据映射以供后续的逆向工程操作使用。 您可随时在 设置中更改它们。

将数据库视图映射到 JPA 实体

IntelliJ IDEA 遵循所有最佳实践,在逆向工程时为数据库视图提供最有效的映射:

  1. 由于数据库视图没有主键,IntelliJ IDEA 允许您选择一个字段或一组字段作为目标实体的标识符。

  2. 大多数 DB 视图是不可变的。 因此,IntelliJ IDEA 向实体添加 @Immutable 注解并且仅生成getters。 这有助于提高应用程序性能。

  3. IntelliJ IDEA 只会为映射到数据库视图的实体生成一个无参数的受保护构造函数,根据 JPA 规范,这防止了开发人员在业务逻辑代码中创建这些实体的新实例

逆向工程列

有些开发人员更喜欢 DB-first 应用程序开发方法。 首先, 他们直接向数据库添加列,然后更新 JPA 模型。 IntelliJ IDEA 可以自动化此过程。

从数据库生成属性

  1. 如果未建立数据库连接, 创建一个

  2. 持久性 工具窗口中,展开 JPA 节点,右键点击实体,然后选择 新建 | 从数据库中获取 JPA 实体

    或者,在您的实体源代码中,点击装订线中的实体图标 实体图标 ,然后选择 从数据库创建实体特性

  3. 请选择一个数据库连接、一张表或一个视图,并选择要映射的列。 属性迁移流程与 Entities from DB wizard 部分中描述的相同。

    数据库对话框中的实体属性

从 MongoDB 生成属性

  1. 如果未建立数据库连接, 创建一个

  2. 持久性 工具窗口中,展开 Spring Data MongoDB 节点,右键点击实体,然后选择 新建 | 来自数据库的 MongoDB 字段

    来自数据库的 MongoDB 文档
  3. 请选择一个数据库连接、一张表或一个视图,并选择要映射的列。 属性迁移流程与 Entities from DB wizard 部分中描述的相同。

    来自数据库的 MongoDB 文档

智能引用检测

IntelliJ IDEA 深刻理解您的模型。 在某些情况下,可以正确检测基数: @OneToOne@OneToMany@ManyToOne@ManyToMany。 最酷的是,IntelliJ IDEA 即使在当前表格中没有相应列的情况下也能显示引用。

让我们更仔细地看看这些情况。

@OneToOne

在两种情况下,我们可以自信地假设关系的基数为 @OneToOne

  1. 表中有一列带有唯一约束,引用了另一个表的主键

  2. 表的主键是外键

情况 1:

CREATE TABLE profiles ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, join_date date, user_id BIGINT, status VARCHAR(255), bio VARCHAR(255), CONSTRAINT pk_profiles PRIMARY KEY (id) ); CREATE TABLE users ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, last_name VARCHAR(255), first_name VARCHAR(255), CONSTRAINT pk_users PRIMARY KEY (id) ); ALTER TABLE profiles ADD CONSTRAINT uc_profiles_user UNIQUE (user_id); ALTER TABLE profiles ADD CONSTRAINT FK_PROFILES_ON_USER FOREIGN KEY (user_id) REFERENCES users (id);
one-to-one-uc-diagram.jpeg
one-to-one-uc-wizard

IntelliJ IDEA将在 User 实体中生成一个 @OneToOne 关联,具有一个 @JoinColumn 注解,并在 Profile 实体中生成一个 @OneToOne 关联,具有一个 mappedBy 参数:

@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "profile_id") private Profile profile; } @Entity @Table(name = "profiles") public class Profile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @OneToOne(fetch = FetchType.LAZY, mappedBy = "profile") private User users; }

案例编号 2:

CREATE TABLE users ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, last_name VARCHAR(255), first_name VARCHAR(255), CONSTRAINT pk_users PRIMARY KEY (id) ); CREATE TABLE profiles ( user_id BIGINT NOT NULL, status VARCHAR(255), bio VARCHAR(255), join_date date, CONSTRAINT pk_profiles PRIMARY KEY (user_id) ); ALTER TABLE profiles ADD CONSTRAINT FK_PROFILES_ON_USER FOREIGN KEY (user_id) REFERENCES users (id);
one-to-one-pk-fk-diagram.jpeg
one-to-one-pk-fk-wizard.jpeg

由于 @Id 不应是持久化实体,IntelliJ IDEA 将生成:

  • 基本类型的 id 属性并使用 @Id 注解对其进行标记

  • users@OneToOne 关联并使用 @MapsId 注解标记

@Entity @Table(name = "profiles") public class Profile { @Id @Column(name = "user_id", nullable = false) private Long id; @MapsId @OneToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id", nullable = false) private User users; //... } @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @OneToOne(fetch = FetchType.LAZY, mappedBy = "user") private Profile profiles; //... }

@OneToMany & @ManyToOne

如果一个表具有指向另一个表的主键的列,则很可能是一个 @ManyToOne 关联。 但是您也可以根据需要将基数更改为 @OneToOne。 因此,取决于您在哪个表上调用反向工程操作,IntelliJ IDEA 将检测映射类型为 @OneToMany@ManyToOne

CREATE TABLE users ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, last_name VARCHAR(255), first_name VARCHAR(255), CONSTRAINT pk_users PRIMARY KEY (id) ); CREATE TABLE profiles ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, join_date date, status VARCHAR(255), bio VARCHAR(255), user_id BIGINT, CONSTRAINT pk_profiles PRIMARY KEY (id) ); ALTER TABLE profiles ADD CONSTRAINT FK_PROFILES_ON_USER FOREIGN KEY (user_id) REFERENCES users (id);
one-to-many-many-to-one-diagram
one-to-many-many-to-one-wizard

IntelliJ IDEA 将生成以下代码:

@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @OneToMany(mappedBy = "user") private Set<Profile> profiles = new LinkedHashSet<>(); //... } @Entity @Table(name = "profiles") public class Profile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") private User user; //... }

@ManyToMany

要在两张表之间建立多对多关系,您需要使用连接表。 在这种情况下,连接表只包含两列——外键。 IntelliJ IDEA 能够自动检测这样的表,并识别两个表之间的关系基数,这两个表的 ids 在连接表中表示为外键,如 @ManyToMany

CREATE TABLE users ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, last_name VARCHAR(255), first_name VARCHAR(255), CONSTRAINT pk_users PRIMARY KEY (id) ); CREATE TABLE profiles ( id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, join_date date, status VARCHAR(255), bio VARCHAR(255), CONSTRAINT pk_profiles PRIMARY KEY (id) ); CREATE TABLE profiles_users ( profile_id BIGINT NOT NULL, users_id BIGINT NOT NULL, CONSTRAINT pk_profiles_users PRIMARY KEY (profile_id, users_id) ); ALTER TABLE profiles_users ADD CONSTRAINT fk_prouse_on_profile FOREIGN KEY (profile_id) REFERENCES profiles (id); ALTER TABLE profiles_users ADD CONSTRAINT fk_prouse_on_user FOREIGN KEY (users_id) REFERENCES users (id);
many-to-many-diagram
many-to-many-wizard

如果任何实体中不存在此关联,IntelliJ IDEA 将在调用反向工程操作的实体中生成该关联。

@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @ManyToMany @JoinTable(name = "profiles_users", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "profile_id")) private Set<Profile> profiles = new LinkedHashSet<>(); //... }

如果此关联已经存在于其中一个实体中,那么 IntelliJ IDEA 将生成带有 @ManyToMany 属性和 mappedBy 参数的属性。

@Entity @Table(name = "profiles") public class Profile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; @ManyToMany(mappedBy = "profiles") private Set<User> users = new LinkedHashSet<>(); //... }

设置

常规

  1. 提取类型. 为遵循最佳实践并避免潜在的性能问题,IntelliJ IDEA 默认为 FetchType.LAZY 设置 @OneToOne@ManyToOne 关联。

  2. 验证注解。 验证注解为您提供了除数据库约束之外的另一层保护。 默认情况下,IntelliJ IDEA 会在反向工程过程中将这些注释应用于实体属性。

  3. 复数形式。 默认情况下,IntelliJ IDEA 使用实体名称的单数形式。 例如,如果您有一个名为 users 的表,IntelliJ IDEA 将生成一个 用户 实体。 如果您禁用此选项,IntelliJ IDEA 将保留表格的原始名称,并且仅将首字母大写——Users

  4. 基本类型属性。 当此选项启用时,IntelliJ IDEA 将分析数据库模式中的 ORM 引用,并生成基本类型属性,而不是在实体之间创建关联或关系。 在某些场景下,当您更喜欢简单的属性类型而不是复杂的关联时,这可能会很有用。

反向工程设置.png

表格和列注释

为了保留添加到数据库对象的注释,IntelliJ IDEA 会根据您的设置,通过 Hibernate @Comment 注释或 JavaDocs 将其传输到相应的实体。

偏好设置-注释

命名规则

通过 Configs

命名规则

通常,DBA 专家会遵循特定的数据库对象命名规范。 例如,所有表或列名都有特定的前缀/后缀。 然而,Java 开发人员通常更喜欢在 JPA 模型中删除这些前缀/后缀。 IntelliJ IDEA 允许您指定要跳过的前缀和后缀。 假设我们设置 sys_p_ 作为要跳过的前缀。 之后,我们将对 sys_userp_product 表格应用逆向工程。 因此,前缀不会出现在相应的实体名称中。 最终实体名称将是 用户Product 而不是 SysUserPProduct。 此外,数据库列名有时会与 保留的 Java 关键字相匹配。 例如, public接口 等等。 在这种情况下,您可以配置字段后缀,以便 IntelliJ IDEA 将它附加到原始列名称。 例如,对于 字段 后缀,生成的名称将是 publicFieldinterfaceField

通过算法

命名规则

尽管有灵活的选项来配置前缀、后缀、保留字等,但在某些情况下,这仍然可能不足。 IntelliJ IDEA 不会仅限于这些设置。 您可以编写自定义代码来处理数据库表/列的名称。 此外,您不仅可以在当前编辑器中编写代码,还可以导入现有类并使用其方法。

请注意,IntelliJ IDEA 不会实时跟踪命名算法中使用的类的更改。 因此,在更改算法中使用的类后,请更新您的设置或重启 IntelliJ IDEA。

类型映射

preferences-mapping-types

当应用程序使用多个 DBMS 时,您的架构可能会针对每个 DBMS 拥有略微不同的数据类型。

假设应用程序需要同时支持 PostgreSQL 和 MS SQL,并且需要在字符串数据中存储 Unicode 字符。 PostgreSQL 支持 Unicode 字符 VARCHAR ,但 MS SQL 有一个单独的数据类型 NVARCHAR

IntelliJ IDEA 允许您为每个 DBMS 指定类型映射。 还可以为 JPA 转换器和 Hibernate 类型设置映射:

了解如何在 IntelliJ IDEA 中配置类型映射以便在 Hibernate 6 中使用 @JavaType 注解:

最后修改日期: 2025年 4月 24日