当前位置: 首页 > 知识库问答 >
问题:

Hibernate不允许保存引用未保存瞬态实例的对象的原因是什么?

屈畅
2023-03-14

我是Hibernate的新手,我正在努力学习JPA和Hibernate。

我想知道Hibernate不允许保存引用未保存的瞬态实例的对象的原因是什么?我想知道为什么这是一个问题?

我问了一个人,他们中的一些人这样回答我:

如果数据库中还没有地址记录,我们怎么可能将客户映射到地址?

您正在为客户分配特定地址。但地址没有任何ID

但老实说,我不理解他们。

(我知道会抛出异常,解决方案是级联,但我想在数据库中说明问题的原因)

现在,假设我们有所有这些代码:

(我以双向一对一关系为例)

public class Customer {

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

    private String firstName;
    private String lastName;


    @OneToOne(mappedBy = "customer")
    private Address address;
}

--

@Entity
public class Address { 

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

    @OneToOne
    private Customer customer;
}

--

   public static void main(String[] args) {

        EntityManager entityManager = emf.createEntityManager();
        entityManager.getTransaction().begin(); // Begin Transaction

        Customer c1 = new Customer("Mi", "S");
        Address addrss1 = new Address("5412 S 5th", "212524");

        c1.setAddress(addrss1);
        addrss1.setCustomer(c1);


        entityManager.persist(c1);

        entityManager.getTransaction().commit(); // Commit 
        entityManager.close();
    }

让我们假设没有抛出异常,并且java和hibernate允许我们运行我们的代码,这是我们的客户表。

   id    firstName    lastName    
---------------------------------
    1        Mi           S

现在,问题是什么?这种双向一对一关系中的一切似乎都是正确的。那问题是什么?

共有1个答案

臧烨烁
2023-03-14

客户是新的,从你想要插入它的持久调用中可以清楚地看出,但是不清楚你想要对任何客户的引用发生什么。为了清楚起见,你定义了你希望JPA提供者(Hibernate)在任何/所有情况下在映射中做什么-这就是级联操作所指的。在这种情况下,JPA将查看customer.addressOneToOne映射,发现没有任何定义;Address不在这个EntityManager上下文中进行管理,因此它不知道如何处理这种关系,因此它通过抛出错误来表明你犯了错误。

如果它让它通过,您的客户实例引用了不存在的东西,并且它的状态与数据库中的内容不匹配。您传递给持久化的应该是您在读取时会返回的内容,因此它应该反映数据库中的状态。请记住,JPA在实体身份方面非常重要,因为这允许在多级缓存中缓存这些实体,并且该实体可能会按原样进入这些缓存。它必须知道如何处理对不存在的实体的引用,并且规范决定要求例外。

问题并不直接与您的持久化调用有关,因为规范确实允许提供者忽略对没有级联设置的分离/新实例的引用——发生的事情只是未定义。在这种情况下,您出错的地方是刷新/提交,即持久化单元同步到数据库(JPA 3.0的第3.2.4节),这要求提供者通过托管实体,然后确定任何更改。在持久化之前添加新地址将导致与在持久化之后添加相同的问题,并且要求提供者在发现新的或删除的实体并回滚事务时抛出IllegalStateException。

 类似资料: