为啥 Hibernate 允许我在外键约束上插入空值?

Posted

技术标签:

【中文标题】为啥 Hibernate 允许我在外键约束上插入空值?【英文标题】:Why does Hibernate allow me to insert a null value on a foreign key constraint?为什么 Hibernate 允许我在外键约束上插入空值? 【发布时间】:2017-10-01 23:20:06 【问题描述】:

我正在试验 jpa 和休眠关系。我正在使用一个名为 users 的表和一个名为 emails 的表。一个用户可以有许多电子邮件。

当我运行 Spring Boot 应用程序和以下代码时,我在我的 h2 数据库中获得了一条电子邮件记录。该记录的 email_address 为 testAddress,该记录的 user_username 列为空。 user_username 列在 emails 表中列为外键。我的问题是,为什么emailRepository.save(email1) 在数据库中没有对应用户的情况下会成功?

@Entity
@Table(name = "emails")
public class Email 

    @Id
    private String emailAddress;

    @ManyToOne
    private User user;

    ...



@Entity
@Table(name = "users")
public class User 

    @Id
    private String username;

    @OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
    private Set<Email> emails;

    ...



public interface UserRepository extends JpaRepository<User, String> 



public interface EmailRepository extends JpaRepository<Email, String> 



@Component
public class UserRepositoryCommandLineRunner implements CommandLineRunner 

    @Autowired
    private EmailRepository emailRepository;

    public void run(String... args) throws Exception 
        Email email1 = new Email();
        email1.setEmailAddress("testAddress");
        emailRepository.save(email1);
    


【问题讨论】:

猜你的意思是保存方法完成但事务提交失败?或者新行提交正常,外键为空? 新行提交正常,外键为空。 当我转到localhost:8080/h2-console -> EMAILS -> 索引 ->FK... 时,它显示为一个名为 USER_USERNAME 的 FK,其属性非唯一。我假设这意味着我与 users 表有外键关系。 如果我将用户 id="testUser" 设置为 id="testAddress" 的电子邮件并保存该电子邮件,那么应用程序会抱怨找不到 testUser。所以这很好。我不确定是否可以向已经具有关系注释的内容添加非空约束。我不认为它应该让我添加一个空值吗? 【参考方案1】:

看一下JoinColumn注解的文档: https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html#nullable()

提到:

如果 JoinColumn 注释本身是默认的,则单个连接列 假定并应用默认值。

由于您没有在 ManyToOne 映射中指定 JoinColumn,因此 Hibernate 将假定默认的 JoinColumn。如果您查看JoinColumn.nullable 属性,它默认为true。因此,当 Hibernate 生成您的模式时,外键列默认为 NULLABLE。

您可能需要在 @ManyToOne 映射之上显式添加 @JoinColumn 注释并将其 nullable 属性设置为 false。

@ManyToOne
@JoinColumn(nullable=false)
private User user;

这样,当您尝试在没有用户的情况下插入电子邮件时,它会抛出错误。

【讨论】:

实际上,使用@ManyToOne(optional=false) 可能更有意义。它将在应用程序级别强制执行一致性,甚至无需访问数据库

以上是关于为啥 Hibernate 允许我在外键约束上插入空值?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 EF 在外键上允许空值?

Oracle SQL Developer - 在外键上添加约束

jOOQ loadInto 不会在外键约束上抛出错误失败

复合唯一键约束,其中一列中包含多个空值

oracle 如何创建,可空唯一约束

mysql约束