拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Hibernate中Session的对象状态

Hibernate中Session的对象状态

白鹭 - 2021-11-24 507 0 0

1.简介

Hibernate是用于管理持久性数据的便捷框架,但是有时了解其内部工作方式可能很棘手。

在本教程中,我们将学习对象状态以及如何在它们之间移动。我们还将研究分离实体可能遇到的问题以及如何解决它们。

2. Hibernate的Session

Session接口是用于与Hibernate通信的主要工具。它提供了一个API,使我们能够创建,读取,更新和删除持久对象。该session具有简单的生命周期。我们打开它,执行一些操作,然后关闭它。

session期间我们对对象进行操作时,它们会附加到该session 。我们所做的更改将在关闭时被检测并保存。关闭后,Hibernate断开对象与会话之间的连接。

3.对象状态

在Hibernate的Session上下文中,对象可以处于三种可能的状态之一:临时,持久或分离。

3.1 短暂Transient

我们尚未附加到任何session的对象处于过渡状态。由于它从未被持久保存,因此它在数据库中没有任何表示形式。由于没有session知道它,因此不会自动保存它。

让我们用构造函数创建一个用户对象,并确认它不是由会话管理的:

Session session = openSession();

 UserEntity userEntity = new UserEntity("John");

 assertThat(session.contains(userEntity)).isFalse();

3.2 Persistent持久

session相关联的对象处于持久状态。我们要么保存它,要么从持久性上下文中读取它,因此它表示数据库中的某些行。

让我们创建一个对象,然后使用persist方法将其持久化:

Session session = openSession();

 UserEntity userEntity = new UserEntity("John");

 session.persist(userEntity);

 assertThat(session.contains(userEntity)).isTrue();

或者,我们可以使用save方法。区别在于, persist方法将只保存一个对象,而save方法将另外生成其标识符(如果需要)。

3.3 Detached分离

当我们关闭session ,其中的所有对像都将分离。尽管它们仍然代表数据库中的行,但是它们不再由任何session管理:

session.persist(userEntity);

 session.close();

 assertThat(session.isOpen()).isFalse();

 assertThatThrownBy(() -> session.contains(userEntity));

接下来,我们将学习如何保存临时实体和分离实体。

4.保存并重新连接实体

4.1 保存瞬态实体

让我们创建一个新实体并将其保存到数据库中。当我们第一次构造对象时,它将处于过渡状态。

为了persist我们的新实体,我们将使用persist方法:

UserEntity userEntity = new UserEntity("John");

 session.persist(userEntity);

现在,我们将创建另一个标识符,该标识符与第一个相同。第二个对象是临时的,因为它尚未由任何session管理,但是我们不能使用persist方法将其持久化。它已经在数据库中表示出来,因此在持久层的上下文中并不是真正的新事物。

相反,我们将使用merge方法更新数据库并使对象持久化

UserEntity onceAgainJohn = new UserEntity("John");

 session.merge(onceAgainJohn);

4.2。保存分离Detached的实体

如果关闭上一个session ,则对象将处于分离状态。与前面的示例类似,它们在数据库中表示,但是当前不受任何session管理。 merge方法使它们再次持久化:

UserEntity userEntity = new UserEntity("John");

 session.persist(userEntity);

 session.close();

 session.merge(userEntity);

5.嵌套实体

当我们考虑嵌套实体时,事情变得更加复杂。假设我们的用户实体还将存储有关其经理的信息:

public class UserEntity {

 @Id

 private String name;



 @ManyToOne

 private UserEntity manager;

 }

保存此实体时,我们不仅需要考虑实体本身的状态,还需要考虑嵌套实体的状态。让我们创建一个持久的用户实体,然后设置其管理器:

UserEntity userEntity = new UserEntity("John");

 session.persist(userEntity);

 UserEntity manager = new UserEntity("Adam");

 userEntity.setManager(manager);

如果我们现在尝试更新它,我们将得到一个例外:

assertThatThrownBy(() -> {

 session.saveOrUpdate(userEntity);

 transaction.commit();

 });
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.baeldung.states.UserEntity.manager -> com.baeldung.states.UserEntity

之所以会这样,是因为Hibernate不知道如何处理瞬时嵌套实体。

5.1 持久化嵌套实体

解决此问题的一种方法是显式保留嵌套实体:

UserEntity manager = new UserEntity("Adam");

 session.persist(manager);

 userEntity.setManager(manager);

然后,在提交事务之后,我们将能够检索正确保存的实体:

transaction.commit();

 session.close();



 Session otherSession = openSession();

 UserEntity savedUser = otherSession.get(UserEntity.class, "John");

 assertThat(savedUser.getManager().getName()).isEqualTo("Adam");

5.2 级联操作

如果我们在实体类中正确cascade属性,则可以自动持久保存临时嵌套实体:

@ManyToOne(cascade = CascadeType.PERSIST)

 private UserEntity manager;

现在,当我们持久化对象时,该操作将级联到所有嵌套实体:

UserEntityWithCascade userEntity = new UserEntityWithCascade("John");

 session.persist(userEntity);

 UserEntityWithCascade manager = new UserEntityWithCascade("Adam");



 userEntity.setManager(manager); // add transient manager to persistent user

 session.saveOrUpdate(userEntity);

 transaction.commit();

 session.close();



 Session otherSession = openSession();

 UserEntityWithCascade savedUser = otherSession.get(UserEntityWithCascade.class, "John");

 assertThat(savedUser.getManager().getName()).isEqualTo("Adam");

6.总结

在本教程中,我们仔细研究了Hibernate Session在对象状态方面的工作方式。然后,我们检查了它可能产生的一些问题以及如何解决它们。

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *