【问题标题】:Seems JPA spring.jpa.hibernate.ddl-auto=update doesn't work似乎 JPA spring.jpa.hibernate.ddl-auto=update 不起作用
【发布时间】:2021-04-02 14:56:30
【问题描述】:

我构建了一个简单的 SpringBoot App(版本:2.4.3)。我有以下实体:

package com.ksteindl.logolo.domain;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Foo {

    @Id
    private String id;
    private String foo;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}

还有一个application.properties

spring.jpa.show-sql=true

spring.datasource.url = jdbc:mysql://localhost:3306/mysql
spring.datasource.username=admin
spring.datasource.password=admin

spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57Dialect

在第一次运行时,一切似乎都很好。这些表是根据实体创建的。 但是,当我重新启动我的应用程序时,我拥有的每个实体/表都会出现异常。此外,如果我修改我的实体(例如在 Foo 实体中引入 bar 属性),相应的表在数据库中没有改变。 在我看来,它试图重新创建表,但我不知道为什么。 我拥有的每个表/实体都有以下例外:

Hibernate: create table foo (id varchar(255) not null, bar varchar(255), baz varchar(255), foo varchar(255), primary key (id)) engine=InnoDB
2021-04-02 16:34:17.000  WARN 16359 --- [  restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl     : GenerationTarget encountered exception accepting command : Error executing DDL "create table foo (id varchar(255) not null, bar varchar(255), baz varchar(255), foo varchar(255), primary key (id)) engine=InnoDB" via JDBC Statement

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table foo (id varchar(255) not null, bar varchar(255), baz varchar(255), foo varchar(255), primary key (id)) engine=InnoDB" via JDBC Statement
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:559) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:504) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.createTable(AbstractSchemaMigrator.java:277) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:71) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:207) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:114) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:184) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:318) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259) [hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) [spring-orm-5.3.4.jar:5.3.4]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) [spring-orm-5.3.4.jar:5.3.4]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) [spring-orm-5.3.4.jar:5.3.4]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) [spring-orm-5.3.4.jar:5.3.4]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) [spring-orm-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) [spring-beans-5.3.4.jar:5.3.4]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1153) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:907) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:582) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.4.3.jar:2.4.3]
    at com.ksteindl.logolo.LogoloApplication.main(LogoloApplication.java:10) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_282]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_282]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_282]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_282]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.3.jar:2.4.3]
Caused by: java.sql.SQLSyntaxErrorException: Table 'foo' already exists
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-java-8.0.23.jar:8.0.23]
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.23.jar:8.0.23]
    at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:762) ~[mysql-connector-java-8.0.23.jar:8.0.23]
    at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:646) ~[mysql-connector-java-8.0.23.jar:8.0.23]
    at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:95) ~[HikariCP-3.4.5.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~[HikariCP-3.4.5.jar:na]
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final]
    ... 40 common frames omitted

有人可以帮帮我吗?谢谢

【问题讨论】:

  • 你是对的。当然application.properties
  • 你可以试试spring.jpa.hibernate.hbm2ddl.auto=update吗?
  • 不幸的是它不起作用。如果我替换,它就像根本没有 ddl 属性一样工作(默认是活动的,比如 spring.jpa.hibernate.ddl-auto=none)。

标签: java mysql spring hibernate jpa


【解决方案1】:

在某些情况下,Hibernate 无法自行对数据库架构进行一些更改。

这就是为什么我们通常尽量不将ddl-auto 设置为update,我们更喜欢使用像liquibase 或flyway 这样的数据迁移工具。

在非常简单的情况下,例如添加一列,Hibernate 会很好地工作,因为它是一个非破坏性更改。另一方面,如果你想删除一列,它会变得更加微妙。在这种情况下,您的 java 实体将不再知道该列,但在数据库中它仍然存在。

这既是一个问题,也是一件好事,因为 Hibernate 确保您不会丢失数据,但这也是没有进行某些更改的原因。

正如我在上面告诉你的,我们更喜欢使用数据迁移工具,这些工具就是为做这类事情而设计的。

例如,您可以看看 Liquibase,这是一个非常好的工具。 以下是一些有用的链接:

但你也可以使用flyway(我不知道):https://flywaydb.org/

最后,这里有一个比较有趣的 Liquibase 和 Flyway 的比较:https://dzone.com/articles/flyway-vs-liquibase

【讨论】:

  • 感谢您的回复!但是,即使我不修改任何内容,也会出现错误。在我看来,从错误来看,Hibernate 试图创建表,但我不知道为什么。表已经创建(在第一次运行期间)。
  • 我刚刚看到你的堆栈跟踪,因为你编辑了你的帖子,如果你仔细看,这是一个警告而不是错误。您可以尝试明确命名所有约束和键吗?因为我认为 Hibernate 试图重新创建它们,但它们已经存在,这是因为你没有明确命名它
  • 是的,但是在该警告之后,抛出异常,并且我的表没有更新。我正在尝试实现一个轻量级的解决方案,这正是 SpringBoot with JPA 所承诺的。为约束命名是我希望为我做 JPA 的事情。当然我可以具体一点,有时候就是这样。但是,我认为问题只是我的新版 SpringBoot 与我的新版 Mysql 不兼容(参见我上面的回复),使用 Postgres 一切正常。
  • 确实有异常,但它在警告日志中。但是如果 Postgres 没有出现这个问题,那它可能确实是一个兼容性问题。无论如何,我认为您可以忽略这些警告或尝试明确命名所有内容,因为它应该可以工作,因为“它们只是”警告。再说一次,我认为你应该看看数据迁移工具,它会让你的生活更轻松;)祝你好运
【解决方案2】:

看起来在 2.4.3 SpringBoot JPA ddl-auto=update 行为不适用于 MySql 8。 在 PostgreSQL 13 中,ddl-auto=update 行为完美运行,没有任何错误。 我的application.yml

spring:
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.PostgreSQLDialect
  datasource:
    url: "jdbc:postgresql://localhost:5432/mydb"
    username: myuser
    password: mypassword

如果有人可以确认/反驳,那将是令人放心的。

【讨论】:

    猜你喜欢
    • 2022-08-11
    • 1970-01-01
    • 2021-09-15
    • 2015-08-26
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多