【发布时间】: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 -> {
};
}
}
乍一看,一切都很好:一行被添加到数据库中,具有正确的 name 和 age=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;
}
我做错了什么?
【问题讨论】:
-
更改为
create或update看看会发生什么。