How does hibernate generate foreign key constraint

2019-04-15 05:04发布

How does hibernate generate foreign key constraint names?

If i do not define a name hibernate generates something like this

CONSTRAINT fk_2ocepcfwpr1v18dg1ieoe6bau

how is this name generated? Maybe from MD5 hash of field names or something like that? I need to know if the name is equal on all instances.

1条回答
Lonely孤独者°
2楼-- · 2019-04-15 05:19

Hibernate generates a constraint name by concatenating table and properties names and convert the result to MD5. It is needed, because of the constraint names length restriction in some databases. For an example, in the Oracle database, a foreign key name length can't be more than 30 symbols length.

This code snippet from Hibernate source 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 );
    }
}

You can generate your own constraint names (unique and foreign key) using ImplicitNamingStrategy. You can refer Hibernate5NamingStrategy , as an example.

查看更多
登录 后发表回答