【问题标题】:Hibernate says that table doesn't exist but it doesHibernate 说该表不存在,但它确实存在
【发布时间】:2015-06-16 10:59:19
【问题描述】:

我遇到了 Hibernate 引发以下错误的问题:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'Library.book' doesn't exist

我的依赖设置看起来像这样(我相信这可能是原因):

compile("org.springframework.boot:spring-boot-starter-web")
testCompile("org.springframework.boot:spring-boot-starter-test") 

compile 'org.springframework:spring-orm:4.1.6.RELEASE'
compile 'org.springframework.data:spring-data-jpa:1.8.0.RELEASE'

compile 'org.hibernate:hibernate-entitymanager:4.3.8.Final'
compile 'org.hibernate:hibernate-core:4.3.8.Final'

compile 'org.apache.commons:commons-dbcp2:2.1'

compile 'mysql:mysql-connector-java:5.1.35'

compile 'org.apache.logging.log4j:log4j-core:2.2'

所以我使用的是 spring-boot-starter-web(使用 Spring CLI 创建的项目),然后添加了针对 Hibernate 和 Spring Data 的 not-spring-boot 依赖项(在不同的项目中使用了完全相同的依赖项集,但是没有 spring-boot-starter-web 并且一切正常)。

在阅读了其他人的问题后,我检查了我的 @EnableJpaRepositories 是否有正确的存储库路径以及 entityManagerFactoryBean 的 packagesToScan 设置是否正确。

我认为 Spring Boot 与其他依赖存在冲突,因为我的配置看起来不错。

我现在将展示一些代码 sn-ps,因为我可能对我的配置的正确性有误;p

预订 MySQL DDL:

CREATE TABLE IF NOT EXISTS `Library`.`Book` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(100) NOT NULL,
  `description` VARCHAR(256),
  `genre` VARCHAR(50) NOT NULL,
  `releaseDate` DATE NOT NULL,
  PRIMARY KEY (`id`)
)

图书实体:

@Entity
@Table(name="Book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String title;
    private String description;
    private String genre;
    @Temporal(TemporalType.DATE)
    private Date releaseDate;
}

EntityManagerFactory bean:

@Bean
@Autowired(required = true)
public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);
    vendorAdapter.setShowSql(false);
    vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
    vendorAdapter.setDatabase(Database.MYSQL);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("pl.com.imralav.library.data.entity");
    factory.setDataSource(dataSource);

    Properties properties = new Properties();
    properties.setProperty("hibernate.generate_statistics", "false");
    properties.setProperty("hibernate.show_sql", "false");

    factory.setJpaProperties(properties);

    factory.afterPropertiesSet();

    return factory.getObject();
}

如果您需要更多信息,请告诉我。

【问题讨论】:

  • 如果你仔细看,'Library.book' 的 book 是小写的。可能与JPA 2.0 & MySQL are not respecting case sensitive table names有关
  • 有一些改进,将数据库名称更改为book后,出现新错误:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'book0_.release_date' in 'field list',我尝试使用@Column(name="releaseDate")注释修复它,但它没有t 工作(就像 @Table(name="Book") 没有)。知道为什么注释会被忽略吗?
  • 通过更改图书架构(release_date 而不是 releaseDate)重新创建数据库后,一切正常。但我不满意,因为我需要知道为什么有些注释有效(比如@Entity,因为这本书被映射到数据库表)而有些没有(比如@Table@Column,他们没有做Hibernate 查找其他表或其他列名)。
  • Spring boot默认的Hibernate命名策略是Hibernate的扩展ImprovedNamingStrategyprefers embedded underscores to mixed case names(即驼峰名转换为下划线)。您可以使用属性spring.jpa.hibernate.naming_strategy 覆盖。顺便说一句,我建议使用下划线和大写/小写名称的命名约定
  • 您能帮我澄清一件事吗?使用 spring boot 时,它会尝试自动配置任何依赖项,不管它是否是 spring-boot 特定的依赖项?到目前为止,我认为要让 spring-boot 进行自动配置,我需要添加一些特殊的 spring-boot 版本的依赖项,比如我现在正在使用的 spring-boot-starter-web,它只会自动配置那些 spring-boot 依赖项.

标签: hibernate spring-boot spring-data-jpa


【解决方案1】:

问题是我对 Spring Boot 的工作原理了解不足。它加载了整套自动配置类,在我的例子中,它为 Hibernate 设置了不正确的命名策略。我所要做的就是排除 Hibernate 自动配置类

@SpringBootApplication(exclude={HibernateJpaAutoConfiguration.class})

突然间,一切都如我所愿。 非常感谢@Nicolas 用他的 cmets 为我指明了正确的方向。

让我吃惊的是根据 Spring Boot 参考:

自动配置是非侵入性的,您可以随时开始定义自己的配置来替换自动配置的特定部分。例如,如果您添加自己的 DataSource bean,默认的嵌入式数据库支持将退出。

但在我的情况下它不起作用。而且它工作得非常好,我只需要“覆盖”正确的 bean(正如@Oliver 指出的那样)

【讨论】:

  • 禁用自动配置有效,如果您坚持公开LocalContainerEntityManagerFactoryBean 而不是EntityManagerFactory 的约定,因为这是Boot 的自动配置当前预计不会找到的。我已经提交了a ticket for Spring boot 也考虑了这种情况,但只需切换到返回LCEMFB 就可以使其按预期工作。
  • @Tomek 您能否详细说明“我只需要“覆盖”正确的 bean(正如 @Oliver 指出的那样)所做的事情?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-07
  • 2018-08-02
  • 2018-12-05
  • 2022-01-13
  • 1970-01-01
  • 2011-05-14
相关资源
最近更新 更多