2015-09-30 1 views
4

J'émigre une application de mise en veille prolongée 4.3 Mise en veille prolongée à 5.0.1-finale J'utilise ImplicitNamingStrategyComponentPathImpl comme mon hibernate.implicit_naming_strategy avec Postgres 9.4.4 et ma compagnie utilise hibernate.hbm2ddl.auto = update pour le déploiement (je sais qu'il est une mauvaise pratique, mais ne peut pas l'aider)Migration vers Hibernate 5

Pendant l'initialisation de la fabrique de sessions, elle renvoie l'erreur ci-dessous. Apparemment, l'alias généré est trop long pour Postgres. Comment allons-nous à propos de cette situation? J'ai essayé d'attribuer une annotation @Table(name=..) pour contourner ce problème, mais la situation s'aggrave au fur et à mesure que toutes les relations deviennent vaines.

Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Unable to execute schema management to JDBC target [create table public.ReferenceDocumentVersion_ReferenceDocumentSourceFilesStoreDescriptor (ReferenceDocumentVersion_unid uuid not null, sourceFilesStore_filesDescriptorMap_unid uuid not null, filesDescriptorMap_KEY text not null, primary key (ReferenceDocumentVersion_unid, filesDescriptorMap_KEY))] 
    at org.hibernate.tool.schema.internal.TargetDatabaseImpl.accept(TargetDatabaseImpl.java:59) 
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.applySqlString(SchemaMigratorImpl.java:371) 
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.applySqlStrings(SchemaMigratorImpl.java:360) 
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.createTable(SchemaMigratorImpl.java:181) 
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.doMigrationToTargets(SchemaMigratorImpl.java:134) 
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.doMigration(SchemaMigratorImpl.java:59) 
    at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:129) 
    at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:97) 
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:481) 
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:802) 
    ... 29 more 
Caused by: org.postgresql.util.PSQLException: ERROR: relation "referencedocumentversion_referencedocumentsourcefilesstoredescr" already exists 
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182) 
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911) 
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173) 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:618) 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:454) 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:382) 
    at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeUpdate(DelegatingStatement.java:228) 
    at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeUpdate(DelegatingStatement.java:228) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at net.bull.javamelody.JdbcWrapper.doExecute(JdbcWrapper.java:404) 
    at net.bull.javamelody.JdbcWrapper$StatementInvocationHandler.invoke(JdbcWrapper.java:129) 
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:286) 
    at com.sun.proxy.$Proxy93.executeUpdate(Unknown Source) 
    at org.hibernate.tool.schema.internal.TargetDatabaseImpl.accept(TargetDatabaseImpl.java:56) 
    ... 39 more 
+0

S'il vous plaît poster toute stacktrace. Et est-ce que changer le paramètre 'hbm2ddl.auto' a un effet? – Lucky

+0

@Lucky Cela fonctionne si je change hbm2ddl.auto pour créer. Mais ne peut pas se permettre de le faire en production car il laisse tomber et recrée les objets db. – ShellDragon

+0

Dans PostgreSQL, la limite de nom est par défaut de 63 caractères. Alors oui, c'est probablement le problème. Le changer nécessite une recompilation. –

Répondre

4

J'ai abordé la situation avec une coutume ImplicitNamingStrategy qui tronque généré par Hibernate identificateurs 64 caractères (longueur MAX pour Postgres).

versions précédentes de Hibernate (4.x) ont rencontré la même erreur, mais ils ne tient pas juste et procède à l'initialisation du SessionFactory. Cependant, Hibernate 5.x a une nouvelle API de démarrage qui lance une exception SchemaManagementException dans de tels cas et abandonne. Les journaux Hibernate de mes scénarios de test sont collés ci-dessous pour référence.

Mise en veille prolongée 4.X

INFO: HHH000396: Updating schema 
Oct 04, 2015 1:38:00 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata 
INFO: HHH000262: Table not found: ReferenceDocumentVersionEntityWithAReallyReallyReallyLongNameBeyondPostGres 
Oct 04, 2015 1:38:00 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata 
INFO: HHH000262: Table not found: ReferenceDocumentVersionEntityWithAReallyReallyReallyLongNameBeyondPostGres 
Oct 04, 2015 1:38:00 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata 
INFO: HHH000262: Table not found: ReferenceDocumentVersionEntityWithAReallyReallyReallyLongNameBeyondPostGres 
Oct 04, 2015 1:38:00 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute 
ERROR: HHH000388: Unsuccessful: create table ReferenceDocumentVersionEntityWithAReallyReallyReallyLongNameBeyondPostGres (unid uuid not null, path text, primary key (unid)) 
Oct 04, 2015 1:38:00 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute 
ERROR: ERROR: relation "referencedocumentversionentitywithareallyreallyreallylongnamebe" already exists 
Oct 04, 2015 1:38:00 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute 
INFO: HHH000232: Schema update complete 

Mise en veille prolongée 5.0.2.Final

Oct 04, 2015 1:39:16 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute 
INFO: HHH000228: Running hbm2ddl schema update 
Oct 04, 2015 1:39:16 PM org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl processGetTableResults 
INFO: HHH000262: Table not found: ReferenceDocumentVersionEntityWithAReallyReallyReallyLongNameBeyondPostGres 
Oct 04, 2015 1:39:16 PM org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl processGetTableResults 
INFO: HHH000262: Table not found: ReferenceDocumentVersionEntityWithAReallyReallyReallyLongNameBeyondPostGres 
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.813 sec <<< FAILURE! 
testApp(org.foobar.AppTest) Time elapsed: 0.788 sec <<< ERROR! 
javax.persistence.PersistenceException: [PersistenceUnit: org.foobar.persistence.default] Unable to build Hibernate SessionFactory 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:877) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:805) 
    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:58) 
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55) 
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39) 
    at org.foobar.AppTest.testApp(AppTest.java:18) 

Solution

  • sur mesure ImplicitN amingStrategy

    package org.foobar.persistence; 
    import org.hibernate.boot.model.naming.Identifier; 
    import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl; 
    import org.hibernate.boot.spi.MetadataBuildingContext; 
    
    public class PGConstrainedImplicitNamingStrategy extends ImplicitNamingStrategyComponentPathImpl { 
    private static final int POSTGRES_IDENTIFIER_MAXLENGTH = 63; 
    public static final PGConstrainedImplicitNamingStrategy INSTANCE = new PGConstrainedImplicitNamingStrategy(); 
    
    public PGConstrainedImplicitNamingStrategy() { 
    
    } 
    
    @Override 
    protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) { 
        return buildingContext.getMetadataCollector() 
          .getDatabase() 
          .getJdbcEnvironment() 
          .getIdentifierHelper() 
          .toIdentifier(stringForm.substring(0, Math.min(POSTGRES_IDENTIFIER_MAXLENGTH, stringForm.length()))); 
    
    }} 
    
  • persistence.xml

    <properties> 
        <property name="hibernate.implicit_naming_strategy" value="org.foobar.persistence.PGConstrainedImplicitNamingStrategy"/> 
    </properties> 
    

Ce n'est pas une solution évolutive à tous, mais aide à garder le show running. La solution permanente consisterait à fournir explicitement des identifiants pour qu'hibernate ne génère pas d'identifiants vraiment longs.

2

La solution de l'OP peut conduire à une collision (c'est pourquoi il l'appelle pas scalable, non?). Explicitement fournissant tous les identificateurs sonnent comme une idée terrible pour moi.Je vous suggère une des façons suivantes

  • fournir une cartographie Map<String, String> tous les noms à quelque chose plus court trop longs
  • raccourcissent tous les noms à POSTGRES_IDENTIFIER_MAXLENGTH - N et trop longs append N caractères générés par le hachage de la coupe loin partie, de sorte que la probabilité des collisions est minimisé
  • Utilisez une fonction abréviation d'identificateur comme {"Reference" -> "Ref", "Document" -> "Doc", ...} et appliquez-la à vos identifiants avant qu'ils ne soient traités, de sorte que vous obteniez RefDocVersion_RefDocSourceFileDescr... au lieu de referencedocumentversion_referencedocumentsourcefilesstoredescr....
  • Pensez à utiliser des noms abrégés dans votre code lui-même. Ceci est souvent déconseillé, car elle conduit facilement à la non-sens incompréhensible, mais à mon humble avis, il augmente lisibilité lorsqu'il est utilisé à droite (utilisez seulement quelques abréviations et les utiliser systématiquement, fournir une liste d'entre eux).
+0

D'accord avec vous @maaartinus. Merci d'avoir réveillé ce fil, de proposer des solutions plus intelligentes et de rendre le monde meilleur. – ShellDragon