实体中的实体与Hibernate中的持久化上下文分离

时间:2017-01-18 15:32:37

标签: java spring hibernate

Hibernate在事务方法中保留修改后的实体,我可以通过使用session#evict(entity)来避免。

如果我将它从持久化上下文中分离出来,那么其中的实体也将被分离?

例如,我有这个类:

@Entity
public class User extends BaseEntity{
      @Column(name = "email")
      private String email;

      @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
      private List<Address> addresses;

      // getters and setters
}

@Entity
public class Address extends BaseEntity{
      @Column(name = "email")
      private String email;

      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "USER_ID")
      private User user;     

      // getters and setters
}

如果我分离用户对象,但更改了其中的地址对象,那么地址是否会在事务结束时保留?像这样:

User user = userDAO.getById(id);
session.evict(user);
Address address = user.getAddresses().get(0);
address.setNumber(number);
addressDAO.saveOrUpdate(address); //will this work?

2 个答案:

答案 0 :(得分:1)

使用EntityManager.createQuery()更新或删除的实体未加载到持久性上下文中,这仅适用于选择查询,以及使用find()merge()时。

执行更新或删除查询后,持久性上下文实际上可能与数据库不同步,因为查询不会更新已加载到持久性上下文中的实体(您需要调用{ {1}}查看更改)。

如果您加载了一些用户(进入持久性上下文),然后执行refresh(),那么您还没有修改持久化上下文中的任何用户,您只修改了数据库。要修改用户,必须通过调用`aUser.setStatus('active')来修改实际管理的实体,当事务提交时,JPA将根据加载时创建的副本检查所有托管实体,如果有任何更改它将进行更新。

如果要将5000个对象加载到Persistence中,JPA可能需要一些时间来运行实体图,并在事务提交时检测更改。如果您没有修改任何内容,并希望加快更改检测,有两种方法可以做到这一点。使用只读查询加载实体,这告诉JPA它不需要保留已加载实体的副本。另一种选择是调用Update User set status='active' where id IN (:ids)以丢弃所有托管实体。但是,如果您对性能感兴趣,最好的解决方案可能是避免将实体加载到持久性上下文中。据我了解你的问题,你需要做一个EntityManager.clear(),为此你只需要用户的id,这样你就不需要加载用户了,你只需要id,因此你可以做{{1 }}

希望这能为您澄清事情:)

编辑:这是从JPA角度编写的,但是对于休眠Update User set ... where id IN (:ids)只是直接转发到List<Long> ids = em.createQuery("select u.id from User u where ...", Long.class).getResultList();,所以行为完全如描述的那样,除了{{ 1}}在本机Hibernate中被称为EntityManager

答案 1 :(得分:0)

自JPA 2.0

以来

给定 EntityManager ,您可以使用要分离的实体作为参数调用detach

void detach(Object entity)

更多 here

如果您使用注入,那么您可以在要分离所需实体的服务中注入EntityManger。