简体   繁体   English

自动休眠索引创建时间过长

[英]Automatic Hibernate index creation too long

I am back with a bug/problem that came to sunlight now. 我回来了,现在遇到了阳光下的错误/问题。 Usually I test the local development and changes on an H2DB but as I know, this has to work on Oracle and MSSQL too. 通常,我在H2DB上测试本地开发和更改,但是据我所知,它也必须在Oracle和MSSQL上工作。 Now testing on oracle again this problem occurred: The Key COR_VIEWSETTINGSCOR_USERSETTINGS_FK0 and COR_VIEWSETTINGSCOR_USERSETTINGS_FK1 are generated automatic and are way too long for an oracle db. 现在再次在oracle上进行测试会出现此问题:密钥COR_VIEWSETTINGSCOR_USERSETTINGS_FK0和COR_VIEWSETTINGSCOR_USERSETTINGS_FK1是自动生成的,对于oracle数据库来说太长了。 To know how these keys are created I will now show you the entities UserSettings and UserViewSettings. 要知道如何创建这些键,我现在将向您显示实体UserSettings和UserViewSettings。 hint: you can overlook the entities and go further to the edits if they confuse you. 提示:您可以忽略实体,如果它们使您感到困惑,则可以继续进行编辑。 maybe you can still help me. 也许您仍然可以帮助我。

UserSettings 用户设置

/**

      The Class UserSettings.

*/
@org.hibernate.envers.Audited
@DataObject( value =  UserSettings.DATA_OBJECT_NAME )
@CRUDDefinition( supportsRead = true, supportsCreate = true, supportsUpdate = true, supportsDelete = true )
@Entity( name = UserSettings.DATA_OBJECT_NAME )
@NamedQuery( name = UserSettings.DATA_OBJECT_NAME, query = "from userSettings e where e.name = :name" )
@javax.persistence.Inheritance( strategy = javax.persistence.InheritanceType.TABLE_PER_CLASS )
@AttributeOverrides( { @AttributeOverride( name = "id", column = @Column( name = "USERSETTINGS_ID" ) )
} )
@Table( name = "COR_USERSETTINGS", indexes = {
  @javax.persistence.Index( name="COR_USERSETTINGS_FK0", columnList = "SETTINGSTYPE_ID" ),
  @javax.persistence.Index( name="COR_USERSETTINGS_FK1", columnList = "USER_ID" ),
}
)
public class UserSettings extends NamedRevisionEntity implements NameSettingsType, NameSettings
{
  /** The Constant serialVersionUID. */
  private static final long serialVersionUID = 1L;

  /** The Constant DATA_OBJECT_NAME. */
  public static final String DATA_OBJECT_NAME = "userSettings";

  @javax.persistence.Basic( fetch = javax.persistence.FetchType.EAGER, optional = false )
  @Column( name = "SETTINGS", nullable = false, unique = false, insertable = true, updatable = true )
  @javax.persistence.Lob
  private java.lang.String settings;

  @javax.persistence.ManyToOne( fetch = javax.persistence.FetchType.EAGER, optional = false )
  @javax.persistence.JoinColumn( name = "SETTINGSTYPE_ID", nullable = false, unique = false, insertable = true, updatable = true )
  private SettingsType settingsType;

  @javax.persistence.ManyToOne( fetch = javax.persistence.FetchType.EAGER, optional = true )
  @javax.persistence.JoinColumn( name = "USER_ID", nullable = true, unique = false, insertable = true, updatable = true )
  private User user;



  public SettingsType getSettingsType()
  {
    return settingsType;
  }

  public void setSettingsType( SettingsType settingsType )
  {
    this.settingsType = settingsType;
  }

  public User getUser()
  {
    return user;
  }

  public void setUser( User user )
  {
    this.user = user;
  }

  public java.lang.String getSettings()
  {
    return settings;
  }

  public void setSettings( java.lang.String settings )
  {
    this.settings = settings;
  }

  @Override
  public String getDataObjectName()
  {
    return DATA_OBJECT_NAME;
  }



  @Override
  public String toString()
  {
    StringBuilder builder = new StringBuilder( super.toString() );

    builder.append( ", " );
    try
    {
        builder.append( ToStringUtils.referenceToString( "settingsType", "SettingsType", this.settingsType ) );
    }
    catch( Exception ex )
    {
      builder.append( ex.getClass().getName()  );
      builder.append( ": " );
      builder.append( ex.getMessage() );
    }
    builder.append( ", " );
    try
    {
        builder.append( ToStringUtils.referenceToString( "user", "User", this.user ) );
    }
    catch( Exception ex )
    {
      builder.append( ex.getClass().getName()  );
      builder.append( ": " );
      builder.append( ex.getMessage() );
    }

    builder.append( "]" );
    return builder.toString();
  }

}

UserViewSettings UserViewSettings

/**

      The Class UserViewSettings.

*/
@org.hibernate.envers.Audited
@DataObject( value =  UserViewSettings.DATA_OBJECT_NAME )
@CRUDDefinition( supportsRead = true, supportsCreate = true, supportsUpdate = true, supportsDelete = true )
@Entity( name = UserViewSettings.DATA_OBJECT_NAME )
@AttributeOverrides( { @AttributeOverride( name = "id", column = @Column( name = "VIEWSETTINGS_ID" ) )
} )
@Table( name = "COR_VIEWSETTINGS", uniqueConstraints = {
  @javax.persistence.UniqueConstraint( name="COR_VIEWSETTINGS_UNQ1", columnNames = { "NAME", "SETTINGSTYPE_ID", "VIEW_NAME", "VIEWTYPE_ID" } ),
}
, indexes = {
  @javax.persistence.Index( name="COR_VIEWSETTINGS_FK0", columnList = "VIEWTYPE_ID" ),
}
)
public class UserViewSettings extends UserSettings implements NameViewName, NameViewType
{
  /** The Constant serialVersionUID. */
  private static final long serialVersionUID = 1L;

  /** The Constant DATA_OBJECT_NAME. */
  public static final String DATA_OBJECT_NAME = "userViewSettings";

  @javax.persistence.Basic( fetch = javax.persistence.FetchType.EAGER, optional = false )
  @Column( name = "VIEW_NAME", nullable = false, unique = false, insertable = true, updatable = true )
  private java.lang.String viewName;

  @javax.persistence.ManyToOne( fetch = javax.persistence.FetchType.EAGER, optional = true )
  @javax.persistence.JoinColumn( name = "VIEWTYPE_ID", nullable = true, unique = false, insertable = true, updatable = true )
  private ViewType viewType;



  public java.lang.String getViewName()
  {
    return viewName;
  }

  public void setViewName( java.lang.String viewName )
  {
    this.viewName = viewName;
  }

  public ViewType getViewType()
  {
    return viewType;
  }

  public void setViewType( ViewType viewType )
  {
    this.viewType = viewType;
  }

  @Override
  public String getDataObjectName()
  {
    return DATA_OBJECT_NAME;
  }



  @Override
  public String toString()
  {
    StringBuilder builder = new StringBuilder( super.toString() );

    builder.append( ", " );
    builder.append( "viewName" );
    builder.append( "=" );
    builder.append( this.viewName );
    builder.append( ", " );
    try
    {
        builder.append( ToStringUtils.referenceToString( "viewType", "ViewType", this.viewType ) );
    }
    catch( Exception ex )
    {
      builder.append( ex.getClass().getName()  );
      builder.append( ": " );
      builder.append( ex.getMessage() );
    }

    builder.append( "]" );
    return builder.toString();
  }

}

Starting Wildfly 10.0.0 with Hibernate 5.2 and an Oracle 11 Database then results in the error that the automatic generated Keys COR_VIEWSETTINGSCOR_USERSETTINGS_FK0 and COR_VIEWSETTINGSCOR_USERSETTINGS_FK1 are naturally too long for the database. 从Hibernate 5.2和Oracle 11数据库启动Wildfly 10.0.0会导致错误,即自动生成的密钥COR_VIEWSETTINGSCOR_USERSETTINGS_FK0COR_VIEWSETTINGSCOR_USERSETTINGS_FK1对于数据库而言太长了。

I took a look at the NamingStrategies for Hibernate and even tried some but they didn't change the error for me. 我看了一下Hibernate的NamingStrategies,甚至尝试了一些,但是它们并没有为我改变错误。

How can I impact the generation of these keys? 我如何影响这些密钥的生成?

EDIT: 编辑:

So turning on DEBUG gave me this: 所以打开调试给了我这个:

2016-11-29 09:22:03,190 DEBUG [org.hibernate.SQL] (ServerService Thread Pool -- 58) create index COR_USERSETTINGS_FK0 on COR_USERSETTINGS (SETTINGSTYPE_ID)
2016-11-29 09:22:03,190 DEBUG [org.hibernate.SQL] (ServerService Thread Pool -- 58) create index COR_USERSETTINGS_FK1 on COR_USERSETTINGS (USER_ID)
2016-11-29 09:22:03,190 DEBUG [org.hibernate.SQL] (ServerService Thread Pool -- 58) create index COR_VIEWSETTINGSCOR_USERSETTINGS_FK0 on COR_VIEWSETT INGS(SETTINGSTYPE_ID)
2016-11-29 09:22:03,190 DEBUG [org.hibernate.SQL] (ServerService Thread Pool -- 58) create index COR_VIEWSETTINGSCOR_USERSETTINGS_FK1 on COR_VIEWSETTINGS (USER_ID)
2016-11-29 09:22:03,190 DEBUG [org.hibernate.SQL] (ServerService Thread Pool -- 58) create index COR_VIEWSETTINGS_FK0 on COR_VIEWSETTINGS (VIEWTYPE_ID)

Now I found the Class ImplicitIndexNameSource in the package org.hibernate.boot.model.naming but the internet doesn't really give examples what I can do with this and it seems to be an empty class for a long since a long time. 现在,我在org.hibernate.boot.model.naming包中找到了ImplicitIndexNameSource类,但是Internet并没有给出我可以使用的示例,而且很长一段时间以来,它似乎一直是一个空类。

EDIT 2: 编辑2:

The previous edit seems to be a wrong path. 先前的编辑似乎是错误的路径。 I found the place where these logs are created. 我找到了创建这些日志的地方。 It's StandardIndexExporter which gets called from SchemaCreatorImpl . 它是从SchemaCreatorImpl调用的StandardIndexExporter So I need to dig even deeper into the framework but if somebody sees this. 所以我需要更深入地研究框架,但是如果有人看到这一点。 Is this the right path? 这是正确的道路吗? Can I modify code so that He will do the thing I want? 我可以修改代码以便他做我想做的事情吗? It seems to be the hbm2ddl that is the culprit since the index get's created in StandardIndexExport in these lines: 罪魁祸首似乎是hbm2ddl ,因为在以下行中在StandardIndexExport中创建了索引get:

final String indexNameForCreation;
if ( dialect.qualifyIndexName() ) {
    indexNameForCreation = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
            new QualifiedNameImpl(
                    index.getTable().getQualifiedTableName().getCatalogName(),
                    index.getTable().getQualifiedTableName().getSchemaName(),
                    jdbcEnvironment.getIdentifierHelper().toIdentifier( index.getName() )
            ),
            jdbcEnvironment.getDialect()
    );
}
else {
    indexNameForCreation = index.getName();
}
final StringBuilder buf = new StringBuilder()
        .append( "create index " )
        .append( indexNameForCreation )
        .append( " on " )
        .append( tableName )
        .append( " (" );

boolean first = true;
Iterator<Column> columnItr = index.getColumnIterator();
while ( columnItr.hasNext() ) {
    final Column column = columnItr.next();
    if ( first ) {
        first = false;
    }
    else {
        buf.append( ", " );
    }
    buf.append( ( column.getQuotedName( dialect ) ) );
}
buf.append( ")" );
return new String[] { buf.toString() };

I would appreciate help a lot. 我将不胜感激。 This is getting really frustrating 这真令人沮丧

So I got it working. 这样我就可以了。 Answering for future people that might find this and have the same issue. 回答可能会发现此问题并且有相同问题的未来人们。

The index key gets created by the dialect of oracle that hibernate is referrencing to. 索引键由hibernate所引用的oracle方言创建。 So what had to be done was implementing an custom OracleDialect that overrides the method getIndexExporter and points to the custom IndexExporter. 因此,要做的是实现一个自定义OracleDialect,该自定义OracleDialect覆盖方法getIndexExporter并指向自定义IndexExporter。 In this IndexExporter you can then modify the way the keys are created. 然后,您可以在此IndexExporter中修改键的创建方式。 In my case I fixed the solution like this: 就我而言,我固定了这样的解决方案:

  /**
   * Gets the correct index name if it is a index for a TABLE_PER_CLASS inheritance and longer than
   * 30 chars.
   *
   * @param index the index to decide for
   * @return the correct index name
   */
  private String getCorrectIndexName( Index index )
  {
    if ( index.getTable() instanceof DenormalizedTable && index.getName().length() > 30 )
    {
      String prefixedTable = index.getTable().getName();
      String tableName = prefixedTable.substring( prefixedTable.indexOf( '_' ) + 1, prefixedTable.length() );
      tableName = shortenName( tableName );
      Iterator<Column> columnItr = index.getColumnIterator();
      String reference;

      if ( columnItr.hasNext() )
      {
        reference = extractReference( columnItr.next() );
      }
      else
      {
        /** backup strategy to prevent exceptions */
        reference = shortenName( NamingHelper.INSTANCE.hashedName( index.getName() ) );
      }

      return tableName + "_" + reference;
    }
    return index.getName();
  }

  /**
   * Extract the reference column of the index and hash the full name before shortening it with
   * shortenName().
   *
   * @param index the index to extract the reference from.
   * @return the reference with an appended _FK(hashedReference).
   */
  private String extractReference( Column column )
  {
    String reference = column.getQuotedName( dialect );
    String md5Hash = NamingHelper.INSTANCE.hashedName( reference );
    md5Hash = md5Hash.substring( md5Hash.length() - 4, md5Hash.length() );
    reference = shortenName( reference );

    return reference + "_FK" + md5Hash;
  }

  /**
   * Shorten the name to a maximum of 11 chars if it's longer.
   *
   * @param reference the reference to shorten
   * @return the shortened string
   */
  private static String shortenName( String reference )
  {
    if ( reference.length() > 11 )
    {
      return reference.substring( 0, 11 );
    }
    return reference;
  }

this had to be called in the Overriden function getSqlCreateStrings . 这必须在Overriden函数getSqlCreateStrings中调用 the changed lines look like this: 更改后的行如下所示:

  String indexName = getCorrectIndexName( index );
  indexNameForCreation = jdbcEnvironment.getQualifiedObjectNameFormatter()
      .format(
          new QualifiedNameImpl( index.getTable().getQualifiedTableName().getCatalogName(),
              index.getTable().getQualifiedTableName().getSchemaName(), jdbcEnvironment.getIdentifierHelper().toIdentifier( indexName ) ),
          jdbcEnvironment.getDialect() );

I hope that helps someone. 希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM