【问题标题】:Hibernate's ddl-auto = validate and column default valuesHibernate 的 ddl-auto = validate 和列默认值
【发布时间】:2021-04-25 04:43:27
【问题描述】:

如何让 Hibernate 在启动时验证列默认值(通过 hibernate.hbm2ddl.auto = validate)?

更新

  • 根据我的分析,我只看到 Hibernate 评估列的类型,仅此而已。见:org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable()
  • 如果我想验证诸如默认值之类的信息,我可能必须编写自己的代码,遍历 Hibernate 实体和数据库表的元模型。

主要问题:

  • 当 Hibernate 实体中的默认值定义与实际数据库的默认值设置不匹配时,Hibernate 不会在启动期间引发错误。我期待看到一个错误。如何确保它被抛出?
  • 当列的数据类型不匹配时,Hibernate 会在启动时抛出错误(这是一件好事)。

下面我将解释所有细节。 您可能只需查看代码 sn-ps 就可以了解我想要了解的内容。


详细信息:MariaDB 命令行

我通过以下方式创建了一个 MariaDB 表:

CREATE TABLE `person2` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` text NOT NULL,
  `age` int(11) DEFAULT 27,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

当我使用 mysql 命令行并手动运行插入语句时,新记录的 age 设置为 27(预期行为):

insert into person2 (name) values ('Bob')

我也可以明确提供年龄,它接受提供的值(预期行为):

insert into person2 (name, age) values ('Joe', 21)

详细信息:休眠

我正在使用 Spring/Hibernate,并创建了以下类以映射到 person2 表:

import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.Type;
import javax.persistence.*;

@Entity
@Table(name = "person2")
@DynamicInsert
public class Person2 {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Type(type = "text")
    @Column(nullable = false)
    private String name;

    @ColumnDefault("27")
    @Column
    private Integer age;

    // Normal getters/setters:

    public void setName(String val) {
        this.name = val;
    }

    public String getName() {
        return this.name;
    }

    public void setAge(Integer val) {
        this.age = val;
    }

    public Integer getAge() {
        return this.age;
    }
}

为了在Spring启动时生成一些测试数据,我有以下几点:

@Configuration
public class DatabaseLoader {

    @Order(1)
    @Bean
    public CommandLineRunner createTestData(Person2Repository person2Repository) {
        Person2 person2 = new Person2();
        person2.setName("hibernate: Bob 10");
        person2Repository.save(person2);

        ...

        return args -> {
        };
    }
}

乍一看,一切都很好:一行被添加到数据库中,具有正确的 nameage=27


休眠阴性测试:

我想确保 Hibernate 的 hibernate.hbm2ddl.auto=validate 工作正常。所以我做了以下事情:

我在实体类中将年龄的类型从 Integer 更改为 Long:

@Entity
@Table(name = "person2")
@DynamicInsert
public class Person2 {
    ...

    @ColumnDefault("27")
    @Column
    private Long age;
}

正如预期的那样,Hibernate 抛出了以下错误:

  • 原因:javax.persistence.PersistenceException:[PersistenceUnit:默认] 无法构建 Hibernate SessionFactory;嵌套异常是 org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: 在表 [person2] 的列 [age] 中遇到错误的列类型;找到 [int (Types#INTEGER)],但期待 [bigint (Types#BIGINT)]

酷,我想抛出那个错误。然后我想测试另一个场景:导致列默认值设置不匹配。但是,当我进行如下所示的修改时,我在启动时没有收到错误(这不是我所期望的):

public class Person2 {
    ...

    @ColumnDefault("999")
    @Column
    private Integer age;
}

当我使用伪造的默认值(非数字)时,Hibernate 甚至没有抛出错误:

public class Person2 {
    ...

    @ColumnDefault("asdf")
    @Column
    private Integer age;
}

所以我想让我们试试columnDefinition 设置默认值的技术。同样,我使用了一个虚假值(见下文)并且 Hibernate 没有抛出错误(这不是我所期望的):

public class Person2 {
    ...

    @Column(columnDefinition = "asdf")
    private Integer age;
}

我做错了什么?

【问题讨论】:

  • 更改为createupdate 看看会发生什么。

标签: java hibernate


【解决方案1】:

首先,您应该知道如何在数据库列中使用默认值。 default 值在将记录保存到该列时没有值时设置在列中,这意味着如果您正在保存记录并且某些属性或列没有值并且您已配置默认值,那么在这种情况下默认值设置为该列,否则设置保存记录时可用的列值。

如果假设您有 column1 并且默认值为 10,那么在将记录写入表时 if column1 is not null then write the value of column1 else write default value 10

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    相关资源
    最近更新 更多