首页 > 代码库 > 【Hibernate步步为营】--核心对象+持久对象全析(二)

【Hibernate步步为营】--核心对象+持久对象全析(二)

      上篇文章讨论了Hibernate的核心对象,在开发过程中经常用到的有JTA、SessionFactory、Session、JDBC,其中SessionFactory可以看做数据库的镜像,使用它能够创建Session对象,JTA用来管理事务,在对象模型修改后同步到数据库中,另外还有Hibernate作为持久层它封装了持久层的转化过程,下面着重讨论持久对象的转换过程。


一、状态解析


      Hibernate的持久对象主要分为三个状态,Transient、Persistent、Detached,其中Transient称为瞬态,没有被数据库管理,Hibernate没有为对象分配id,在数据库中没有对应的行,一般在new出一个对象后转化为瞬态;Persistent称为持久化,此时已经被Session管理,Hibernate为对象分配了一个id(该id可以使用其它方法手动或者自动分配,id的类型可以在User.hbm.xml中配置),在数据库中已经有了对应的一行,在调用session的save方法后会提交到数据库中;Detached称为脱管对象,此时已经将修改同步到了数据库中,它有Hibernate分配的id,但是此时的id是在持久化状态分配的,在编程时此状态的对象往往已经不受session管理,如果想要再次修改可以再次创建一个session,然后管理对象。Transient、Detached的对象如果长时间不使用的话,会在某一时间段被Java的垃圾回收装置进行回收。

  1、Transient:数据库中没有,没有被Session管理


       从Hibernate的体系结构图中不难看出,对象的瞬态是在应用程序中完成的,当对象被创建后即转变为瞬态,它还没有持久化的过程,也就是说并没有持久化标示(id号,Hibernate在创建持久化对象时都会为该对象指定一个id标示,保证唯一性)。瞬态的对象如果没有任何的操作的话,会在某一时刻消亡,并被Java的垃圾回收器回收。

      事例演示:在SessionTest中添加一个名为testSave1的方法,代码如下:
public void testSave1(){
	Session session=null;
	Transaction tx = null;
	try{
		session=HibernateUtils.getSession();
		//开启事务
		tx= session.beginTransaction();
		
		//Transient状态
		User user=new User();
		user.setName("zhangsi");
		user.setPassword("123");
		user.setCreateTime(new Date());
		user.setExpireTime(new Date());
		
	}catch(Exception e){
		e.printStackTrace();
		if(tx != null){
			tx.rollback();
		}
	}finally{
		HibernateUtils.closeSession(session);
	}
	
	//detached状态
}

     在save方法处设置断点,运行调试,输出结果如下图:

   

   2、Persistent:数据库中有,被session管理


        一个瞬态的对象操作完成后需要保存操作,这时候调用save或者其他保存方法时即被转换为持久对象,这时候Hibernate给该对象创建一个持久化标示,并且可能在数据库中有了一个对应行,而且该标示与Java标示(该值表示对象在内存的位置)等价。
       另外一个没有被创建的对象同样可以使用其它的方法来直接转换到该状态,如上图的get、load等方法。persistent状态的对象若发生了改变,则在清理内存时或者在脏数据检查时会把改变同步到数据库中,那么此时会生成两条语句,分别为insert和update。在SessionTest中添加saveTest2方法,测试持久态

public void testSave2(){
		Session session=null;
		Transaction tx = null;
		try{
			session=HibernateUtils.getSession();
			//开启事务
			tx= session.beginTransaction();
			
			//Transient状态
			User user=new User();
			user.setName("zhangsi");
			user.setPassword("123");
			user.setCreateTime(new Date());
			user.setExpireTime(new Date());
			
			//persistent状态
			//persistent状态的对象,当对象的属性发生改变的时候
			//Hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
			session.save(user);
			user.setName("lisi");
			
			//可以显示的调用udpdate方法,因为此时为持久状态,调用udpate没有什么意义
			session.update(user);
			
			tx.commit();
			
		}catch(Exception e){
			e.printStackTrace();
			if(tx != null){
				tx.rollback();
			}
		}finally{
			HibernateUtils.closeSession(session);
		}
}

       调用save方法后进入的持久态,此时的为user对象添加了id标识:
        方法执行完成后会向数据库中添加新的一条信息,细心的童鞋可以看出方法中调用了两次setName方法,最后结果是什么呢,查看mysql中的表可以看到:

      数据库中添加的最后信息是lisi,所以它最后执行了更新操作,此时在控制台中会打印两条sql语句,分别为insert和update语句。
      Note:在提交事务或者关闭Session前,会调用Session的flush方法对每个更改进行操作。

 3、Detached:数据库中有,没有被session管理


       脱管状态下的对象其实已经被映射到了数据库中,只不过此时还没有被垃圾回收期回收,此时的对象拥有持久化标识,该标识对应着数据库中的一行,但是不保证该标识与Java标识对应。
       在SessionTest类中添加testSave3方法,测试Detached状态下对象和数据库,代码如下:

public void testSave3(){
		Session session=null;
		Transaction tx = null;
		User user=null;
		try{
			session=HibernateUtils.getSession();
			//开启事务
			tx= session.beginTransaction();
			
			//Transient状态
			user=new User();
			user.setName("zhangsi");
			user.setPassword("123");
			user.setCreateTime(new Date());
			user.setExpireTime(new Date());
			
			//persistent状态
			//persistent状态的对象,当对象的属性发生改变的时候
			//Hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
			session.save(user);
			user.setName("lisi");
			
			tx.commit();
			
		}catch(Exception e){
			e.printStackTrace();
			if(tx != null){
				tx.rollback();
			}
		}finally{
			HibernateUtils.closeSession(session);
		}
		
		//detached状态
		user.setName("wangwu");
		try{
			session=HibernateUtils.getSession();
			session.beginTransaction();
			
			//将detached状态的对象重新纳入session管理
			//此时将变为persistent状态的对象
			//persistent状态的对象,在清理缓存时会和数据库同步
			session.update(user);
			session.getTransaction().commit();
		}catch(Exception e){
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
		
}

      执行完成后,查看数据库中信息,如下图:

     分析执行结果,不难发现它最后完成的是更新操作,不同的是detached状态下的对象必须重新定义新的Session对象,因为Session对象线程不安全,容易出错。

结语


       上文主要讨论分析了Hibernate持久对象在整个声明周期的状态转化过程,这几种状态的相互转化使得关系模型和对象模型进行了紧密的关联,另外在使用配置文件来管理这几种状态,这样使得Hibernate的操作简单,并且功能强大。上文只是针对持久对象的几种状态做了初步的解析,另外还有状态之间的转化方法将会在下篇文章讨论。