使用Hibernate框架轻松连接数据库(蓝桥杯软件大赛培训教材-Java方向)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.7 持久化类状态

在应用程序中,持久化类的实例可能处于三种的不同状态,Hibernate注重这三种状态及其转换,下面介绍持久化类实例的这三种状态。

1.7.1 三种状态

● 瞬时态(Transient)

也称临时状态,该状态的实例从未与任何持久化上下文(持久化上下文对应于Hibernate中的Session)关联过,不和数据库中的数据有任何关联关系。

● 持久态(Persistent)

持久态实例与某个持久化上下文有关联,它拥有持久化标识(相当于主键值),并且通常在数据库中有一个对应的行。

● 脱管状态(Detached)

也称游离状态,脱管态实例表示曾经与某个持久化上下文发生过关联,不过那个上下文被关闭了。它拥有持久化标识,并且在数据库中通常还存在一个对应的行,只是它已经不在持久化层的管理之下。

1.7.2 三种状态之间的转换

对于持久化过程中对象的生命周期,不同的ORM实现使用不同的术语,定义不同的状态及状态转换。这里将继续使用瞬时、持久、脱管三个术语,介绍对象如何在这三种状态之间转换。

如图1.8所示,可以看到具体的持久管理器(Session)的方法,会触发对象状态的变化。在对象生命周期中,可以从瞬时状态转换到持久状态,再转换到脱管状态。

图1.8 Hibernate中的对象状态及转换

● 瞬时对象

在Hibernate中,使用new操作符初始化的对象,它们的状态是瞬时的。也就是说它们没有跟任何数据库表的行相关联,只要应用不再引用这些对象,它们的状态将会丢失。这时,这些对象的生命期将会终止,变得不可访问,交给垃圾回收机制来回收。瞬时对象状态的修改不能在Hibernate的Session中被持久化。

Hibernate认为所有的瞬时对象都是非事务的,所以Hibernate不能对瞬时对象提供任何回滚功能。另外,仅仅被其他瞬时对象引用的对象也是瞬时的。

把对象从瞬时状态转换为持久状态,可以调用Session的save()或saveOrUpdate()方法。

● 持久对象

在Hibernate中,持久对象是具有数据库标识且在Session中的实例,持久对象有一个主键值设为数据库标识符。持久对象可能来自瞬时对象被save或saveOrUpdate之后形成,也可能是通过get()或load()等方法从数据库中检索出来的对象。

持久对象是同Session相关的,是事务的,它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句把内存中持久对象的状态同步到数据库中。不过,这个过程也可能在其他时间发生,例如Hibernate在执行查询之前可能要求同数据库同步(确保查询能够获得事务早期所做的更改)。通常称已经分配主键值但还没有插入到数据库中的持久对象是新的,新的持久对象将会一直保持“新”的状态直到同步发生。

调用Session的close()和clear()等方法,持久对象脱离Session变成脱管对象,调用Session的delete()方法(数据库中的对应记录已被删除),持久对象变成瞬时对象。

使对象持久化的示例代码如下:

        //省略部分代码
        Session session = sf.openSession();
        Seeker seeker = new Seeker();
        sesssion.save(seeker);
        tx.commit( );
        session.close( );

● 脱管(游离)对象

在Hibernate中,当事务结束时,同Session相关联的持久对象仍然存在(如果事务成功,它们在内存中的状态将会同数据库同步,在数据库中通常会有一条记录对应)。当关闭Session时,这些对象就失去了同Session的关联,一般把这些对象称为脱管对象,表明这些对象的状态不再跟数据库同步(对它的修改仅发生在内存中),也不再在Hibernate持久化层的管理下。

应用程序通常在事务之外还要使用这些脱管对象,当这些对象重新同Session关联时,这些对象又变成了持久状态,例如在事务中调用saveOrUpdate(脱管对象),就会将该脱管对象变成持久对象。

使对象从持久状态到脱管状态再到持久状态的示例代码如下:

        //省略部分代码
        Session sessionOne = sf.openSession();
        Seekerseeker=(Seeker)sessionOne.get(Seeker.class,"替换为id");
        System.out.println(seeker);
        sessionOne.close();                       //seeker对象成为脱管对象
        seeker.setName("zhang");
        seeker.setPassword("zhang");
        Session sessionTwo = sf.openSession();
        sessionTwo.update(seeker);                //重新关联,seeker对象成为持久对象
        sessionTwo.beginTransaction().commit();   //seeker的状态会同步到数据库
        sessionTwo.close();

把持久对象转换为瞬时对象的示例代码如下:

        //省略部分代码
        Session session = sf.openSession();
        Seekerseeker=(Seeker)sessionOne.get(Seeker.class,"替换为id");
        session.delete(seeker);
        session.beginTransaction().commit();
        session.close();
        //在这里还能使用seeker对象,但它已是瞬时状态了

点评

在对象三种状态中,通常最关心的是持久状态的对象,它的最大特点是:对象处于Session管理范围,且状态会同步到数据库中。另外两种状态与之相反,是再普通不过的内存中的对象,不同的是瞬时态的对象没有数据库标识,而脱管状态的对象有数据库标识。