postgresql 迁移到 Hibernate 5

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32864327/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 02:02:52  来源:igfitidea点击:

Migrating to Hibernate 5

javahibernatepostgresqlhibernate-5.x

提问by ShellDragon

I am migrating an application from Hibernate 4.3 to Hibernate 5.0.1-Final I use ImplicitNamingStrategyComponentPathImplas my hibernate.implicit_naming_strategywith Postgres 9.4.4 and my company uses hibernate.hbm2ddl.auto = updatefor deployment ( I know it is a bad practice but cant help it)

我正在将应用程序从 Hibernate 4.3 迁移到 Hibernate 5.0.1-Final 我ImplicitNamingStrategyComponentPathImpl用作我hibernate.implicit_naming_strategy的 Postgres 9.4.4 并且我的公司hibernate.hbm2ddl.auto = update用于部署(我知道这是一个不好的做法,但无能为力)

While the session factory initializes, it throws the below error. Apparently the generated alias is too long for Postgres. How do we go about this situation? I have tried assigning @Table(name=..)annotation to work around this it but it is getting worse as every relationship from that point gets screwd.

当会话工厂初始化时,它会抛出以下错误。显然,生成的别名对于 Postgres 来说太长了。我们如何处理这种情况?我曾尝试分配@Table(name=..)注释来解决这个问题,但随着从那时起的每一个关系都被搞砸,情况变得越来越糟。

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

采纳答案by ShellDragon

I have addressed the situation with a custom ImplicitNamingStrategythat truncates Hibernate generated identifiers to 64 chars (MAX length for Postgres).

我已经通过将ImplicitNamingStrategyHibernate 生成的标识符截断为 64 个字符(Postgres 的最大长度)的自定义解决了这种情况。

Previous versions of Hibernate(4.x) have encountered the same error but they just ignores it and proceeds with initializing the SessionFactory. However, Hibernate 5.x has a new boot strap API which throws a SchemaManagementException in such cases and aborts. Hibernate logs from my test scenarios are pasted below for reference.

以前版本的 Hibernate(4.x) 遇到了同样的错误,但他们只是忽略它并继续初始化 SessionFactory。但是,Hibernate 5.x 有一个新的引导程序 API,它在这种情况下会抛出 SchemaManagementException 并中止。下面粘贴了我的测试场景中的 Hibernate 日志以供参考。

Hibernate 4.X

休眠 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

Hibernate 5.0.2.Final

休眠 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

解决方案

  • Custom ImplicitNamingStrategy

    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>
    
  • 自定义隐式命名策略

    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() ) ) );
    
    }}
    
  • 持久化文件

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

This is not a scalable solution at all but helps to keep the show running. The permanent solution would be to explicitly supply identifiers so that hibernate does not generate really long identifiers.- see the answer written by maaartinus

这根本不是一个可扩展的解决方案,但有助于保持节目的运行。永久的解决方案是显式提供标识符,以便 hibernate 不会生成非常长的标识符。- 见maaartinus写的答案

回答by Spartan

try to follow the Migration guide in Hibernate Documentation in this link

尝试按照此链接中的 Hibernate 文档中的迁移指南进行操作

https://github.com/hibernate/hibernate-orm/blob/5.0/migration-guide.adoc

https://github.com/hibernate/hibernate-orm/blob/5.0/migration-guide.adoc

回答by maaartinus

The OP's solution may lead to collision (that's why he calls it not scalable, right?). Explicitly supplying allidentifiers sound like a terrible idea to me. I'd suggest one of the following

OP 的解决方案可能会导致冲突(这就是为什么他称其为不可扩展的,对吗?)。显式提供所有标识符对我来说听起来是个糟糕的主意。我建议以下之一

  • provide a Map<String, String>mapping all overlong names to something shorter
  • shorten all overlong names to POSTGRES_IDENTIFIER_MAXLENGTH - Nand append Ncharacters generated from the hash of the cut away part, so the probability of collisions gets minimized
  • Use some identifier abbreviating function like {"Reference" -> "Ref", "Document" -> "Doc", ...}and apply it to your identifiers before they get processed, so that you get RefDocVersion_RefDocSourceFileDescr...instead of referencedocumentversion_referencedocumentsourcefilesstoredescr....
  • Consider using abbreviated names in you code itself. This is often advised against, as it easily leads to incomprehensible non-sense, but IMHO it increasesreadability when used right (use only a couple of abbreviations and use them systematically; provide a list of them).
  • 提供Map<String, String>所有超长名称到较短名称的映射
  • 将所有过长的名称缩短为POSTGRES_IDENTIFIER_MAXLENGTH - N并附加N从切掉部分的哈希生成的字符,因此冲突的可能性最小化
  • 使用一些标识符缩写函数,例如{"Reference" -> "Ref", "Document" -> "Doc", ...}在它们被处理之前将它应用到你的标识符上,这样你就会得到RefDocVersion_RefDocSourceFileDescr...而不是referencedocumentversion_referencedocumentsourcefilesstoredescr....
  • 考虑在您的代码中使用缩写名称。通常不建议这样做,因为它很容易导致难以理解的无意义,但恕我直言,如果使用得当,它会增加可读性(仅使用几个缩写并系统地使用它们;提供它们的列表)。