为什么 Spring Boot/JPA 创建这样的约束名称 fkm5pcdf557o18ra19dajf7u26a?

Why Spring Boot/JPA creates constraints names like this fkm5pcdf557o18ra19dajf7u26a?

我有一个名为 City 的实体:

@Entity
@Table (name = "cities")
public class City implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false, columnDefinition = "serial")
    private Long id;

    @Column(nullable = false)
    private String name;    

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false)
    private Department department;

    @Column(nullable = true)
    private Integer code;
}

在这种情况下,如果我没有为字段 Department 指定名称,它会在我的 table "cities" 中创建一个名为 department_id 的字段,没关系,但是当我看到创建的约束时出现一个名为 fkcl2xocc3mnys8b84bw2dog35e 的约束。为什么叫这个名字?有什么意义吗?

这是我的 yaml jpa 配置:

spring:
    profiles: development
    datasource: 
        url: jdbc:postgresql://localhost:5432/lalala
        username: postgres
        password: postgres
        sql-script-encoding: UTF-8
        driver-class-name: org.postgresql.Driver
    data.jpa.repositories.enabled: true
    jpa:
        generate-ddl: true
        hibernate:
            ddl-auto: update
            show_sql: true
            use_sql_comments: true
            format_sql: true
            type: trace
            jdbc.lob.non_contextual_creation: true
            naming:
                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        properties:
            hibernate:
                jdbc.lob.non_contextual_creation: true
                dialect: org.hibernate.dialect.PostgreSQLDialect

这可能是提供商生成的默认名称。您可以使用 ForeignKey 注释来指定名称

@JoinColumn(foreignKey = @ForeignKey(name = "FK_NAME"))

Hibernate 通过连接 table 和属性名称生成约束名称,并将结果转换为 MD5。它是必需的,因为某些数据库中的约束名称长度限制。例如,在 Oracle 数据库中,外键名称长度不能超过 30 个符号长度。

此代码片段来自 Hibernate 源代码org.hibernate.mapping.Constraint

/**
 * If a constraint is not explicitly named, this is called to generate
 * a unique hash using the table and column names.
 * Static so the name can be generated prior to creating the Constraint.
 * They're cached, keyed by name, in multiple locations.
 *
 * @return String The generated name
 */
public static String generateName(String prefix, Table table, Column... columns) {
    // Use a concatenation that guarantees uniqueness, even if identical names
    // exist between all table and column identifiers.

    StringBuilder sb = new StringBuilder( "table`" + table.getName() + "`" );

    // Ensure a consistent ordering of columns, regardless of the order
    // they were bound.
    // Clone the list, as sometimes a set of order-dependent Column
    // bindings are given.
    Column[] alphabeticalColumns = columns.clone();
    Arrays.sort( alphabeticalColumns, ColumnComparator.INSTANCE );
    for ( Column column : alphabeticalColumns ) {
        String columnName = column == null ? "" : column.getName();
        sb.append( "column`" ).append( columnName ).append( "`" );
    }
    return prefix + hashedName( sb.toString() );
}

/**
 * Hash a constraint name using MD5. Convert the MD5 digest to base 35
 * (full alphanumeric), guaranteeing
 * that the length of the name will always be smaller than the 30
 * character identifier restriction enforced by a few dialects.
 * 
 * @param s
 *            The name to be hashed.
 * @return String The hased name.
 */
public static String hashedName(String s) {
    try {
        MessageDigest md = MessageDigest.getInstance( "MD5" );
        md.reset();
        md.update( s.getBytes() );
        byte[] digest = md.digest();
        BigInteger bigInt = new BigInteger( 1, digest );
        // By converting to base 35 (full alphanumeric), we guarantee
        // that the length of the name will always be smaller than the 30
        // character identifier restriction enforced by a few dialects.
        return bigInt.toString( 35 );
    }
    catch ( NoSuchAlgorithmException e ) {
        throw new HibernateException( "Unable to generate a hashed Constraint name!", e );
    }
}

您可以使用 ImplicitNamingStrategy 生成您自己的约束名称(唯一和外键)。你可以参考Hibernate5NamingStrategy ,作为例子。