天天看点

HIbernate中持久化对象的三种状态

持久化对象三种状态的概述

Hibernate为了更好的来管理持久化类,特将持久化类分成了三种状态。在Hibernate中持久化的对象可以划分为三种状态,分别为瞬时态,持久态和脱管态,一个持久化类的实例可能处于三种不同状态中的某一种,三种状态的详细介绍如下。

  • 瞬时态(transient)

    瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象, 不 存 在 持 久 化 标 识 O I D ( 相 当 于 主 键 值 ) , 尚 未 与 H i b e r n a t e S e s s i o n 关 联 \color{red}{不存在持久化标识OID(相当于主键值),尚未与Hibernate Session 关联} 不存在持久化标识OID(相当于主键值),尚未与HibernateSession关联,在数据库中也没有记录,失去引用后将被JVN回收。瞬时状态的对象在内存中是孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。

  • 持久态(persistent)

    持久态的对象 存 在 持 久 化 标 识 O I D , 加 入 到 了 S e s s i o n 缓 存 中 , 并 且 相 关 联 的 S e s s i o n 没 有 关 闭 , 在 数 据 库 中 有 对 应 的 记 录 \color{red}{存在持久化标识OID,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录} 存在持久化标识OID,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的。

  • 脱管态(detached)

    脱管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态。 脱 管 态 对 象 存 在 持 久 化 标 识 O I D , 并 且 仍 然 与 数 据 库 中 的 数 据 存 在 关 联 , 只 是 失 去 了 与 当 前 S e s s i o n 的 关 联 \color{red}{脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联} 脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。

区分对象的三种状态:

配置orm元数据:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itheima.domain" >
	<class name="Customer" table="cst_customer" >
		<id name="cust_id"  >
			<generator class="increment"></generator>
		</id>
		<property name="cust_name" column="cust_name" ></property>
		<property name="cust_source" column="cust_source" ></property>
		<property name="cust_industry" column="cust_industry" ></property>
		<property name="cust_level" column="cust_level" ></property>
		<property name="cust_linkman" column="cust_linkman" ></property>
		<property name="cust_phone" column="cust_phone" ></property>
		<property name="cust_mobile" column="cust_mobile" ></property>
	</class>
</hibernate-mapping>
           

封装Utils工具类:

package pers.zhang.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
  private static SessionFactory sf;
  
  static{
  	//1 创建,调用空参构造
  	Configuration conf = new Configuration().configure();
  	//2 根据配置信息,创建 SessionFactory对象
  	 sf = conf.buildSessionFactory();
  }
  
  //获得session => 获得全新session
  public static Session openSession(){
  			//3 获得session
  			Session session = sf.openSession();
  			
  			return session;
  	
  }
  //获得session => 获得与线程绑定的session
  public static Session getCurrentSession(){
  	//3 获得session
  	Session session = sf.getCurrentSession();
  	
  	return session;
  }
}
           

测试方法:

package pers.zhang.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import pers.zhang.domain.Customer;
import pers.zhang.utils.HibernateUtils;

//测试对象的三种状态
public class Demo {

	@Test
	public void fun1(){
		//1 获得session
		Session session = HibernateUtils.openSession();
		//2 控制事务
		Transaction tx = session.beginTransaction();
		//3执行操作
		Customer c = new Customer(); //瞬时状态对象:没有持久化标识OID,没有被session管理。
		
		c.setCust_name("联想"); // 瞬时状态
		
		session.save(c); // 持久态对象:有持久化标识OID,被session管理。
		
		//4提交事务.关闭资源
		tx.commit();
		session.close();//脱管态对象:有持久化标识OID,没有被session管理。
			
	}
}
           

customer对象由new关键字创建,此时还未与Session进行关联,它的状态称为瞬时态;在执行了session.save(customer)操作后,book对象纳入了Session的管理范围,这时的customer对象变成了持久态对象,此时Session的事务还没有被提交;程序执行完了commit() 操作并关闭了Session后,customer对象与Session的关联被关闭,此时customer对象就变成了脱管态。

持久化对象的三种状态转换

持久化对象的状态演化图:

HIbernate中持久化对象的三种状态

从图中可以看出,当一个对象被执行new关键字创建后,该对象处于瞬时态;

当对瞬时态对象执行Session的save() 或saveOrUpdate()方法后,该对象将被放入Session的一级缓存,对象进入持久态;当对持久态对象执行evict()、close()或clear()操作后,对下个进入脱管态;当直接执行Session的get()、load()、find()或iterate()等方法从数据库里查询对象时,查询到的对象也处于持久态;

当对数据库中的记录进行update()、saveOrUpdate()以及lock()等操作后,此时脱管态的对象就会过渡到持久态;

由于瞬时态和脱管态的对象不在session的管理范围,所以会在一段时间后被JVM回收。

持久化对象的三种状态可以通过调用Session中的一系列方法实现状态间的转换,具体如下:

1. 瞬时态转换到其它状态

瞬时态的对象由new关键字创建,瞬时态对象转换到其它状态总结如下:

  • 瞬时态转换为持久态:

    执行Session的save()或saveOrUpdate()方法。

  • 瞬时态转换为脱管态:

    为瞬时态对象设置持久化标识OID。

    由于持久化对象状态演化图中没有涉及到瞬时态转换到脱管态的情况,这里做下简要说明:脱管态对象存在OID,但是没有Session的关联,也就是说脱管态和瞬时态的区别就是OID有没有值,所以可以同故宫为瞬时态对象设置OID,使其变成脱管态对象。

Customer customer = new Customer();//瞬时态
	customer.setCust_id(1);//脱管态
           

2.持久态对象转换到其它状态

持久化对象可以直接通过Hibernate中Session的get()、load()方法,或者Query查询从数据库中获得,持久态对象转换到其他状态总结如下:

  • 持久态转换为瞬时态:

    执行Session的delete()方法,需要注意的是被删除的持久化对象,不建议再次使用。

  • 持久态转换为脱管态:

    执行Session的evict()、close()或clear()方法。evict()方法用于清除一级缓存中某一个对象;close()方法用于关闭Session,清除一级缓存;clear()方法用于清除一级缓存的所有对象。

3.脱管态对象转换到其他状态

脱管态对象无法直接获得,是由其他状态对象转换而来的,脱管态对象转换到其他状态总结如下:

  • 脱管态转换为持久态:

    执行Session的update()、saveOrUpdate()或lock()方法。

  • 脱管态转换为瞬时态:

    将脱管态对象的持久化标识OID设置为null。

    由于持久化对象状态演化图中没有涉及到脱管态转换到瞬时态的情况,这里做下简要说明:跟瞬时态转换到脱管态的情况相似,脱管态和瞬时态的区别就是OID有没有值,所以可以通过将脱管态对象的OID设置为null,使其编程瞬时态对象。

    例如:在session.close()操作后,加入代码

    customer.setCust_id(null);

    customer对象将由脱管态转为瞬时态。

持久态对象能够自动更新数据库

持久态对象其实有一个非常重要的特性:持久化对象可以自动更新数据库。

@test
	//测试持久化类的持久态对象有自动更新数据库的能力
	public void demo2(){
	Session session = HibenateUtils.openSession();
	Transaction tx = session.geginTransaction();
	
	//获得持久态的对象
	Customer customer = session.get(Customer.class, 1L);//持久态对象
	customer.setCust_name("小明");

	//session.update(customer);不用手动调用update方法就可以更新

	tx.commit();
	session.close();
	}
           

执行测试我们会发线,我们并没有手动调用update方法,Hibernate就可以将数据自动更新了。持久态对象就有这样一个功能。持久态对象之所以有这样的功能其实都依赖了Hibernate的一级缓存。

继续阅读