【问题标题】:Hibernate 4 -> 5 migration: NamingStrategy changes, Tables not foundHibernate 4 -> 5 迁移:NamingStrategy 更改,未找到表
【发布时间】:2016-06-25 05:10:13
【问题描述】:

我想做什么

我正在尝试从 WildFly 8.2.0 迁移到 WildFly 10.0.0,这意味着我已经(并且想要)从 Hibernate 4.3 迁移到 Hibernate 5.0。

设置

Java 8u40 
Spring 4.1.9 
SQL Server 2012
Wildfly 8.2.0 -> Wildfly 10.0.0 
Hibernate 4.3.6 -> Hibernate 5.0.7

我已经阅读了migration guide 并且对命名策略 的更改感到震惊。我havereadmanyquestions关于这个,但我的似乎有点不同。 Hibernate 抱怨找不到表:

INFO [o.h.Version] HHH000412: Hibernate Core {5.0.7.Final}
INFO [o.h.cfg.Environment] HHH000206: hibernate.properties not found
INFO [o.h.cfg.Environment] HHH000021: Bytecode provider name : javassist
INFO [o.h.annotations.common.Version] HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
INFO [o.h.dialect.Dialect] HHH000400: Using dialect: org.hibernate.dialect.SQLServerDialect
INFO [o.h.envers.boot.internal.EnversServiceImpl] Envers integration enabled? : true
INFO [o.h.validator.internal.util.Version] HV000001: Hibernate Validator 5.2.3.Final
INFO [o.h.tool.hbm2ddl.SchemaValidator] HHH000229: Running schema validator
INFO [o.h.t.s.e.i.InformationExtractorJdbcDatabaseMetaDataImpl] HHH000262: Table not found: SEC_AUTHORIZATION_RULES
INFO [o.h.t.s.e.i.InformationExtractorJdbcDatabaseMetaDataImpl] HHH000262: Table not found: SEC_USER
More tables not found ...
INFO [o.h.hql.internal.QueryTranslatorFactoryInitiator] (ServerService Thread Pool -- 62) HHH000397: Using ASTQueryTranslatorFactory

当我切换到调试日志记录时,我看到例如他将实体绑定到正确的数据库表:

DEBUG [o.h.c.a.EntityBinder] Bind entity com.company.user.User on table SEC_USER
DEBUG [o.h.c.Ejb3Column] Binding column: Ejb3Column{table=org.hibernate.mapping.Table(SEC_USER), mappingColumn=ID, insertable=true, updatable=true, unique=false}

对我来说奇怪的是该应用程序可以正常工作。在此Table not founds 之后,它不会抱怨架构不正确。该应用程序有效。选择、插入、更新数据有效。

我已经通过它的 spring-orm 抽象配置了休眠:

@Bean(name = "myEmf")
@DependsOn({"dataSource", "flyway"})
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPackagesToScan(new String[]{"com.company.**.*"});
    em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    em.setJpaProperties(additionalProperties());
    return em;
}

private Properties additionalProperties() {
  Properties propFile = propertiesFile();
  properties.setProperty("hibernate.hbm2ddl.auto", "validate");
  properties.setProperty("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");
  properties.setProperty("hibernate.show_sql", "false");
  properties.setProperty("hibernate.format_sql", "true");
  properties.setProperty("hibernate.id.new_generator_mappings", "false");
  properties.setProperty("hibernate.use_sql_comments", "false");
  properties.setProperty("hibernate.implicit_naming_strategy", "legacy-jpa");
  return properties;
}

在这个对应的实体中,我有明确命名的表名和列名:

@Entity
@Table(name = "SEC_USER")
public class User extends BaseEntity {

   @Column(name = "LOGIN", nullable = false, unique = true)
   private String login;

问题

  • 如何使未找到此表的日志消息消失?
  • 如果我有明确命名的表名,为什么它们会出现?
  • 他为什么不抱怨列名?
  • 为什么他看起来工作正常

我尝试过的

  • 将 Spring 4.1.9 升级到 4.2.5 says he has support for Hibernate 5
  • 根据thishibernate.implicit_naming_strategy设置为legacy-jpa
  • 手动设置默认架构并分配角色 db_owner。请注意,在使用休眠 4 之前,我从来没有这样做过。

  • 我已经对 hibernate 进行了一些调试,并且我在 InformationExtractorJdbcDatabaseMetaDataImpl.java 中发现 hibernate 看不到目录(无论是什么)和架构。至少我认为他应该看到架构。请参见下面的屏幕截图:目录和架构为空。

【问题讨论】:

    标签: java spring hibernate wildfly hibernate-5.x


    【解决方案1】:

    从 Hibernate 5 开始,NamingStrategy 的逻辑分为两个概念:隐式和物理。您已正确设置隐式命名策略,但尚未设置 Physical 策略。 Hibernate 没有提供兼容的,所以你必须自己创建一个:

    public class LegacyPhysicalNamingStrategy implements PhysicalNamingStrategy {
        private final Pattern pattern = Pattern.compile("(\\p{Lower}+)(\\p{Upper}+)");
        public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
            return convert(name);
        }
    
        public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironmen) {
            return convert(name);
        }
    
        public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironmen) {
            return convert(name);
        }
    
        public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironmen) {
            return convert(name);
        }
    
        public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironmen) {
            return convert(name);
        }
    
        private Identifier convert(Identifier identifier) {
            if (identifier == null || identifier.getText().trim().isEmpty()) {
                return identifier;
            }
    
            String text = identifier.getText();
            text =  pattern.matcher(text).replaceAll("$1_$2").toLowerCase();
            return Identifier.toIdentifier(text, identifier.isQuoted());
        }
    
    }
    

    通过将属性 hibernate.physical_naming_strategy 设置为上述类的完全限定类名来更改为使用它。

    【讨论】:

    • 我已经验证了这一点,但事实并非如此。就我而言,它似乎是 JDBC 驱动程序。
    【解决方案2】:

    使用最新的 SQL Server JDBC 驱动程序解决了这个问题。 A 有一个 2012 年的旧版本。现在我从https://www.microsoft.com/en-us/download/details.aspx?id=11774 (sqljdbc_4.2.6420.100_enu.exe -> sqljdbc42.jar) 下载并使用了最新的 JDBC 4.2,它开始工作了。我什至可以恢复 SQL 用户的默认架构更改。

    【讨论】:

    • 嗯。这真的没有意义。你确定你没有同时尝试多件事吗? SQL-driver 版本应该与此无关。
    • 是的,真的。我恢复了关于架构的所有更改,只留下了hibernate.implicit_naming_strategy 集,然后来回切换 JDBC 驱动程序,仅此而已。也许stackoverflow.com/users/1025118/vlad-mihalcea 会看到这个帖子并对此发表评论:)
    【解决方案3】:

    我正在解决同样的问题,但使用 jtds 驱动程序。经过一番研究,我发现,SqlServerDialect 的休眠使用sp_tables 存储过程来查找表声明。在该 SP 中,第二个参数是模式名称,因此,如果它是 null,则表搜索工作正常,如果它为空字符串 - 则不是。

    Hibernate 在两种情况下将此参数设置为null

    • 如果方言方法getNameQualifierSupport()返回NameQualifierSupport.CATALOG,但所有SqlServerDialects都返回null
    • 如果驱动程序在 'supportsSchemasInTableDefinitions()' 方法中返回 false,但 jtds 返回 true

    为了解决这个问题,我决定扩展SqlServer2012Dialect end override getNameQualifierSupport() 方法。

    public class SqlServer2012DialectWithCatalogOnly extends SQLServer2012Dialect {
        @Override
        public NameQualifierSupport getNameQualifierSupport() {
            return NameQualifierSupport.CATALOG;
        }
    }
    

    并将属性hibernate.dialect 设置为新类org.company.SqlServer2012DialectWithCatalogOnly

    希望这会有所帮助...

    【讨论】:

      【解决方案4】:

      我想你们都会有兴趣知道,我已经记录了以下票:

      https://hibernate.atlassian.net/browse/HHH-11424

      将 JTDS 更新为 microsoft JDBC 驱动程序将为您提供实现 Connection.getSchema() 的驱动程序,显然,解决该问题,正如报告的那样。

      但是,如果您确实更新了该驱动程序,并且您依赖 default_schema 来有效地更改引用位置表的位置(例如,它不会查看当前用户的默认“dbo”架构),那么您如果不提供自定义的 SchemaNameResolver,仍然会不走运。

      所有这一切中真正令人烦恼的是implicitSchemaName 在验证期间从未被应用。

      【讨论】:

        【解决方案5】:

        我有类似的问题,我是这样解决的:

        jpaProperties.put("hibernate.hbm2ddl.jdbc_metadata_extraction_strategy", "individually")

        【讨论】:

          猜你喜欢
          • 2017-09-08
          • 2015-09-30
          • 2013-10-16
          • 1970-01-01
          • 2015-12-18
          • 1970-01-01
          • 2022-12-12
          • 1970-01-01
          • 2021-05-23
          相关资源
          最近更新 更多