1. 创建你的自定义排序策略类

需要创建一个 Java 类,实现 org.hibernate.boot.model.relational.ColumnOrderingStrategy 接口。 因为这里只排序创建表的字段顺序,这里继承原有默认的方式 org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard 类,重写 orderTableColumns 方法。

package ink.metoo.gude.hibernate.strategy;

import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SimpleColumnOrderingStrategy extends ColumnOrderingStrategyStandard {

    @Override
    public List<Column> orderTableColumns(Table table, Metadata metadata) {
        return table.getColumns().stream()
                .sorted(new SimpleColumnComparator(metadata))
                .collect(Collectors.toList());
    }

    private static class SimpleColumnComparator extends ColumnOrderingStrategyStandard.ColumnComparator {
  
        // 排在最末尾的字段
        private static final String[] END_COLUMN = {"last_modified_date", "create_date"};

        public SimpleColumnComparator(Metadata metadata) {
            super(metadata);
        }

        @Override
        public int compare(Column o1, Column o2) {
            // identity column first
            if (o1.isIdentity() && !o2.isIdentity()) return 0;
            if (o1.isIdentity()) return -1;
            if (o2.isIdentity()) return 1;

            // end column last
            boolean o1Contains = Arrays.asList(END_COLUMN).contains(o1.getName());
            boolean o2Contains = Arrays.asList(END_COLUMN).contains(o2.getName());

            if (o1Contains && o2Contains) return 0;
            if (o1Contains) return 1;
            if (o2Contains) return -1;

            return super.compare(o1, o2);
        }
    }
}

1.1. 关于排序逻辑的说明

  • orderTableColumns 方法接收一个 Table 对象和该表中的 Column 对象列表。
  • 你需要返回一个排序后的 Column 对象列表。
  • 实现自定义排序逻辑的关键是使用 java.util.Comparator。在 Comparator 内部,你可以根据 Column 对象的属性(如 getName())来定义排序规则。
  • 注意: 像“保持 JPA 实体中字段的声明顺序”这种需求,单纯通过 ColumnOrderingStrategy 实现会非常困难,甚至不可能。因为 Hibernate 在构建其内部元数据模型时,已经失去了 Java 源代码中字段的声明顺序信息。ColumnOrderingStrategy 只能对 Hibernate 已经识别到的列进行排序,而不是改变它识别列的方式。

2. 在 Spring Boot 配置中引用它

spring:
  jpa:
    properties:
      hibernate:
        column_ordering_strategy: ink.metoo.gude.hibernate.strategy.SimpleColumnOrderingStrategy

在你的 application.propertiesapplication.yml 文件中,将 spring.jpa.properties.hibernate.column_ordering_strategy 属性设置为你刚刚创建的自定义类的完全限定名。

2.1. 注意

spring.jpa.properties.hibernate.column_ordering_strategy 这个属性用于配置 Hibernate 6.2 及更高版本中列的排序策略。它允许你自定义 Hibernate 在生成数据库 DDL 时表中列的物理顺序。

3. 测试与验证

  • 启动你的 Spring Boot 应用程序。
  • 确保 spring.jpa.hibernate.ddl-auto 被设置为 createcreate-drop,这样 Hibernate 会重新生成 Schema。
  • 使用数据库客户端工具连接到你的数据库,并查看由 Hibernate 生成的表的 DDL (Data Definition Language) 或者表结构,验证列的顺序是否按照你的 CustomColumnOrderingStrategy 中的定义进行了排序。