前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊hibernate的hbm2ddl的实现

聊聊hibernate的hbm2ddl的实现

作者头像
code4it
发布2018-09-17 15:24:26
4230
发布2018-09-17 15:24:26
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究下hibernate的hbm2ddl

SchemaManagementTool

hibernate-core-5.0.12.Final-sources.jar!/org/hibernate/tool/schema/spi/SchemaManagementTool.java

代码语言:javascript
复制
public interface SchemaManagementTool extends Service {
    public SchemaCreator getSchemaCreator(Map options);
    public SchemaDropper getSchemaDropper(Map options);
    public SchemaMigrator getSchemaMigrator(Map options);
    public SchemaValidator getSchemaValidator(Map options);
}

这个tool定义了create、drop、migrate、validate四个功能。

SchemaCreatorImpl

hibernate-core-5.0.12.Final-sources.jar!/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java

代码语言:javascript
复制
public class SchemaCreatorImpl implements SchemaCreator {

    @Override
    public void doCreation(Metadata metadata, boolean createNamespaces, List<Target> targets) throws SchemaManagementException {
        doCreation( metadata, createNamespaces, targets.toArray( new Target[ targets.size() ] ) );
    }
    //......
}

主要逻辑在doCreation里头,里头按如下顺序创建:

  • 创建catalog/schema
  • 创建before table auxiliary objects
  • 创建sequences
  • 创建tables
    • 创建indexes
    • 创建uniques
  • 创建foreign keys
  • 创建after table auxiliary objects

它们又主要借助dialect的各种exporter来实现

Dialect

hibernate-core-5.0.12.Final-sources.jar!/org/hibernate/dialect/Dialect.java

代码语言:javascript
复制
public abstract class Dialect implements ConversionContext {
    //......
    // DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    private StandardTableExporter tableExporter = new StandardTableExporter( this );
    private StandardSequenceExporter sequenceExporter = new StandardSequenceExporter( this );
    private StandardIndexExporter indexExporter = new StandardIndexExporter( this );
    private StandardForeignKeyExporter foreignKeyExporter = new StandardForeignKeyExporter( this );
    private StandardUniqueKeyExporter uniqueKeyExporter = new StandardUniqueKeyExporter( this );
    private StandardAuxiliaryDatabaseObjectExporter auxiliaryObjectExporter = new StandardAuxiliaryDatabaseObjectExporter( this );
    //......
}

这里定义了table、sequence、index、foreign key、unique key、auxiliary database object的exporter

StandardTableExporter

hibernate-core-5.0.12.Final-sources.jar!/org/hibernate/tool/schema/internal/StandardTableExporter.java

代码语言:javascript
复制
public class StandardTableExporter implements Exporter<Table> {
   //.....
    @Override
    public String[] getSqlCreateStrings(Table table, Metadata metadata) {
        final QualifiedName tableName = new QualifiedNameParser.NameParts(
                Identifier.toIdentifier( table.getCatalog(), table.isCatalogQuoted() ),
                Identifier.toIdentifier( table.getSchema(), table.isSchemaQuoted() ),
                table.getNameIdentifier()
        );

        final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment();
        StringBuilder buf =
                new StringBuilder( tableCreateString( table.hasPrimaryKey() ) )
                        .append( ' ' )
                        .append(
                                jdbcEnvironment.getQualifiedObjectNameFormatter().format(
                                        tableName,
                                        jdbcEnvironment.getDialect()
                                )
                        )
                        .append( " (" );

        boolean isPrimaryKeyIdentity = table.hasPrimaryKey()
                && table.getIdentifierValue() != null
                && table.getIdentifierValue().isIdentityColumn( metadata.getIdentifierGeneratorFactory(), dialect );
        // this is the much better form moving forward as we move to metamodel
        //boolean isPrimaryKeyIdentity = hasPrimaryKey
        //                && table.getPrimaryKey().getColumnSpan() == 1
        //                && table.getPrimaryKey().getColumn( 0 ).isIdentity();

        // Try to find out the name of the primary key in case the dialect needs it to create an identity
        String pkColName = null;
        if ( table.hasPrimaryKey() ) {
            Column pkColumn = (Column) table.getPrimaryKey().getColumns().iterator().next();
            pkColName = pkColumn.getQuotedName( dialect );
        }

        final Iterator columnItr = table.getColumnIterator();
        boolean isFirst = true;
        while ( columnItr.hasNext() ) {
            final Column col = (Column) columnItr.next();
            if ( isFirst ) {
                isFirst = false;
            }
            else {
                buf.append( ", " );
            }
            String colName = col.getQuotedName( dialect );

            buf.append( colName ).append( ' ' );

            if ( isPrimaryKeyIdentity && colName.equals( pkColName ) ) {
                // to support dialects that have their own identity data type
                if ( dialect.getIdentityColumnSupport().hasDataTypeInIdentityColumn() ) {
                    buf.append( col.getSqlType( dialect, metadata ) );
                }
                buf.append( ' ' )
                        .append( dialect.getIdentityColumnSupport().getIdentityColumnString( col.getSqlTypeCode( metadata ) ) );
            }
            else {
                buf.append( col.getSqlType( dialect, metadata )  );

                String defaultValue = col.getDefaultValue();
                if ( defaultValue != null ) {
                    buf.append( " default " ).append( defaultValue );
                }

                if ( col.isNullable() ) {
                    buf.append( dialect.getNullColumnString() );
                }
                else {
                    buf.append( " not null" );
                }

            }

            if ( col.isUnique() ) {
                String keyName = Constraint.generateName( "UK_", table, col );
                UniqueKey uk = table.getOrCreateUniqueKey( keyName );
                uk.addColumn( col );
                buf.append(
                        dialect.getUniqueDelegate()
                                .getColumnDefinitionUniquenessFragment( col )
                );
            }

            if ( col.getCheckConstraint() != null && dialect.supportsColumnCheck() ) {
                buf.append( " check (" )
                        .append( col.getCheckConstraint() )
                        .append( ")" );
            }

            String columnComment = col.getComment();
            if ( columnComment != null ) {
                buf.append( dialect.getColumnComment( columnComment ) );
            }
        }
        if ( table.hasPrimaryKey() ) {
            buf.append( ", " )
                    .append( table.getPrimaryKey().sqlConstraintString( dialect ) );
        }

        buf.append( dialect.getUniqueDelegate().getTableCreationUniqueConstraintsFragment( table ) );

        applyTableCheck( table, buf );

        buf.append( ')' );

        if ( table.getComment() != null ) {
            buf.append( dialect.getTableComment( table.getComment() ) );
        }

        applyTableTypeString( buf );

        List<String> sqlStrings = new ArrayList<String>();
        sqlStrings.add( buf.toString() );

        applyComments( table, tableName, sqlStrings );

        applyInitCommands( table, sqlStrings );

        return sqlStrings.toArray( new String[ sqlStrings.size() ] );
    }
}

上面的sql生成具体还根据传入的dialect来实现不同数据库的语句的区别。

小结

要实现一个ddl的功能,一个要有不同的dialect来屏蔽不同数据库的区别,另外一个就是需要创建索引、序列、主键、外键等相关的对象,其他的就是字段类型的映射。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SchemaManagementTool
  • SchemaCreatorImpl
  • Dialect
  • StandardTableExporter
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档