为什么Hibernate允许在外键约束上插入空值?

3
我正在尝试使用jpa和hibernate来处理关系。我使用了一个名为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);
    }

}

你的意思是保存方法已经完成,但事务提交失败了吗?还是新行已经成功提交,但外键为空? - Nathan Hughes
新行已提交,外键为空。 - TheWebCoder
当我访问http://localhost:8080/h2-console/ -> EMAILS -> Indexes -> FK时,它显示为名为USER_USERNAME的FK,并且具有非唯一属性。我假设这意味着我与用户表之间存在外键关系。 - TheWebCoder
如果我将用户ID设置为“testUser”的电子邮件ID为“testAddress”,并保存该电子邮件,则应用程序会抱怨找不到testUser。所以这很好。我不确定是否可以向已经具有关系注释的内容添加非空约束。虽然我认为它不应该让我添加空值? - TheWebCoder
1个回答

3
请查看JoinColumn注释的文档: https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html#nullable() 文档中提到: 如果JoinColumn注释本身已被默认,则假定有一个单一的连接列,并应用默认值。
由于您在ManyToOne映射中没有指定JoinColumn,Hibernate将默认使用JoinColumn。如果您查看JoinColumn.nullable属性,则默认为true。因此,当Hibernate生成模式时,默认情况下外键列是可空的。
您可能需要在ManyToOne映射上方显式添加@JoinColumn注释并将其nullable属性设置为false。
@ManyToOne
@JoinColumn(nullable=false)
private User user;

这样做可以在您尝试插入没有用户的电子邮件时抛出错误。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接