带@ColumnDefault的HIbernate列不能为空

时间:2018-04-02 10:02:18

标签: mysql spring hibernate spring-boot orm

我的应用程序在Spring Boot中使用了hibernate。

我创建了一个这样的表:

public class TopicSubscriberMap implements Serializable
{   
    @ColumnDefault(value="'pending'")
    @Column(nullable=false)
    private String status;
    ...
}

该表在mysql中创建如下:

mysql> desc topic_subscriber_map;
+---------------+--------------+------+-----+---------+-------+
| Field         | Type         | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| status        | varchar(255) | NO   |     | pending |       |
+---------------+--------------+------+-----+---------+-------+

保存表格如下:

TopicSubscriberMap tsm = new TopicSubscriberMap();
tsm = mapRepository.save(tsm);

我收到错误:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'status' cannot be null

如果我将字段设为可为空,那么虽然该表已被保存,但在db中,

+--------+
| status | 
+--------+
| NULL   | 
+--------+

为什么@ColumnDefault不起作用?我的错误在哪里?

修改 当我删除@ColumnDefault并将列声明为

private String status = "pending"

然后虽然默认值有效,但表架构显示:

+---------------+--------------+------+-----+---------+-------+
| Field         | Type         | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| status        | varchar(255) | NO   |     | NULL    |       |
+---------------+--------------+------+-----+---------+-------+

如何使默认值有效并将其显示在表架构中?

1 个答案:

答案 0 :(得分:0)

因此,您在这里使用2种不同的方法来设置默认值:通过DB和通过Java。两种方法都不相互协调,并且如果配置了其他方法,则一种方法不会受到影响。我会解释。

@ColumnDefault一起使用的第一种方法是 DB方法。使用columnDefinition的{​​{1}}属性可以实现相同的行为。在这里,JPA只需将此值添加到DB中字段的列定义中。但是,Hibernate在准备查询时不考虑数据库定义,而是将null值从Java对象转录为准备好的SQL查询,导致查询执行时@Column。有关更多信息,请点击此处:Hibernate Guide

您使用的第二种方法依赖于 Java初始化。当您调用MySQLIntegrityConstraintViolationException时,您的实体对象将获得默认值。但是您的数据库不知道或不关心它,因为它的列定义没有受到影响。

解决方案

如果要在数据库上设置默认值,并且还可以在应用程序中使用它们,则可以使用Hibernate的new TopicSubscriberMap();批注

@DynamicInsert

这将解决您的两个问题,尽管在某些情况下会带来一系列性能问题,这些问题在此线程中讨论:Why does Hibernate set dynamic insert=false by default