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

       上篇文章讨论了Hibernate持久对象的生命周期,在整个生命周期中一个对象会经历三个状态,三种状态的转换过程在开发过程中是可控的,而且是通过使用方法来控制它们的转化过程,具体的转化过程今天就来着重讨论下。


二、状态转化方法


       前面说到对象之间的转化过程是通过使用方法来实现的,这些方法是很重要的,先看张图

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

     上面这张图在三篇文章中都有用到,它详细描述了持久对象三种状态的转换过程及具体的转化方法,另外还有垃圾回收器,对象在瞬态和脱管状态下如果长时间不适用将会在某一时刻被Java回收器回收,消亡。


  1、对象直接进入Persistent状态         

    

     1.1 get方法

         从数据库中获取一行信息,并将该信息同步到创建的对象中,该方法返回一个Object对象,如果没有查询到内容则返回null。下面的实例通过采用Session的get方法来获取一个对象,并将对象转换为实例。

public void testGet1(){
	Session session=null;
	Transaction tx = null;
	try{
		session=HibernateUtils.getSession();
		//开启事务
		tx= session.beginTransaction();
		//get加载上来的对象为持久对象
		//执行get会马上发出查询语句,如果不存在会返回null
		User user=(User)session.get(User.class,"ff80808145bc28cc0145bc28ce020002");
		System.out.println(user.getName());
		
		//persistent状态
		//persistent状态的对象,当对象的属性发生改变的时候
		//Hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
		user.setName("赵柳");
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		if(tx != null){
			tx.rollback();
		}
	}finally{
		HibernateUtils.closeSession(session);
	}	
}

        设置断点,获取User对象。            

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


       获取到了该对象,通过强制转换后得到了一个user对象。程序中添加了setName方法,也就是说会更新数据库中的名称,执行完成后检查数据库,如下图更新结果。                        【Hibernate步步为营】--核心对象+持久对象全析(三)

   1.2 load方法

     功能类似于get方法,也是从数据库中获取数据并同步到对象中,该方法支持lazy是一种懒汉操作,它返回的是一个持久化的Object对象或者一个代理,所以需要进行转化。

public void testLoad1(){
	Session session=null;
	try{
		session=HibernateUtils.getSession();
		//不会马上查询语句,因为load支持lazy(延迟加载/懒加载)
		//什么教lazy?只有真正使用这个对象的时候,再创建,对于Hibernate来说
		//才真正发出查询语句,主要为了提高性能,lazy是Hibernate中非常重要的特性
		//Hibernate的lazy是如何实现的?采用代理对象实现,代理对象主要采用的是CGLIB库生成的
		//而不是JDK的动态代理,因为JDK的动态代理只能对实现了借口的类生成代理,CGLIB可以对类生成
		//代理,它采用的是继承方式
		User user=(User)session.load(User.class,"8a1b653745bcc7b50145bcc7b7140001");
		System.out.println(user.getName());
		
		//persistent状态
		//persistent状态的对象,当对象的属性发生改变的时候
		//Hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
		user.setName("zhaoliu");
		
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
	}finally{
		HibernateUtils.closeSession(session);
	}	
}

        查询获取该User对象如下图:

           【Hibernate步步为营】--核心对象+持久对象全析(三)
        分析上图,获取的User对象并不完整,或者说并没有常见一个User对象,更是一种代理,它使用了CGLIB来预加载对象,只有在使用该对象时才真正创建。


    1.3 Get Vs load


       get和load方法很重要,在面试Hibernate时经常会考到,下面对比下两者。
       相同点:(1)功能相同,将关系数据转化为对象;

                       (2)使用方法相同,同样需要制定两个参数
       不同点:(1)load方法支持lazy操作,预加载对象,在使用时才创建,get是直接将关系数据转化为对象;

                       (2)load加载对象如果不存在会抛出objectNotFoundException异常,get如果没有获取数据会返回null。


  2、手动构造detached对象

        想要获取对象还有另外一种方法,它区别于get与load方法,是一种手动获取的方法,首先常见一个对象,然后通过制定id的方式获取该对象的数据,方法如下:

public void testUer(){
	Session session=null;
	try{
		
		session=HibernateUtils.getSession();
		session.beginTransaction();
		
		//手动构造detached对象
		User user=new User();
		user.setId("8a1b653745bcc7b50145bcc7b7140001");
		
		//persistent状态
		//persistent状态的对象,当对象的属性发生改变的时候
		//Hibernate在清理缓存(脏数据检查)的时候,会和数据库同步
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
	}finally{
		HibernateUtils.closeSession(session);
	}	
}

        查看获取的结果图:

          【Hibernate步步为营】--核心对象+持久对象全析(三)
                    
       分析结果图,代码中使用了setId方法为该对象制定了id号,在制定id号后就能够对该对象进行操作,在事务提交后同步到数据库中,采用了手动指定,手动指定了对象的信息。

    2.1 Delete方法

       删除数据库中指定的对象,在删除前必须将对象转化到Persistent状态,可以使用get、load或者手动的方法指定对象,使用方法如下代码:

session=HibernateUtils.getSession();
session.beginTransaction();
User user=(User)session.load(User.class,"8a1b653745bcc6d50145bcc6d67a0001");
//建议采用此种方式删除,先加载再删除
session.delete(user);

   2.2 Update

      更新数据,该方法会修改数据库中的数据。在使用的时候会出现量中情况,更新数据库某个字段值或者更新数据库的整行值

     2.2.1  更新某个字段值

      如果只想要更新某个字段的值,在update前,需要使用load或者get方法使对象转化为persistent状态代码如下:

//获取session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//或者可以使用另外的方法开启
//session.getTransaction().begin();

//加载获取User对象
//方法一:使用load方法
//User user=(User)session.load(User.class, "8a1b653745bcc7b50145bcc7b7140001");
//方法二:手动获取
User user=new User();
user.setId("8a1b653745bcc7b50145bcc7b7140001");

//更新姓名
user.setName("zhangsan");
session.update(user);
session.getTransaction().commit();

      2.2.2 更新整行                        

      想要更新整行的数据,可以采用手动将状态转换到detached状态,手动指定对象的id值,代码如下:

//获取session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//或者可以使用另外的方法开启
//session.getTransaction().begin();

//手动获取
User user=new User();
user.setId("8a1b653745bcc7b50145bcc7b7140001");

//更新姓名
user.setName("zhangsan");
session.update(user);
session.getTransaction().commit();

       查看更新结果:

        【Hibernate步步为营】--核心对象+持久对象全析(三)
      分析更新结果,它其实更新了数据库的整行数据,这种更新操作有太多的不确定因素,不建议使用。


   2.3 save方法


        插入数据。在执行save方法时会调用数据库的insert语句,向数据库中添加新的一行。save后的对象会转化为持久态,在此状态下的对象能够再次更新对象,在最后提交事务时会同更改更新到数据库。如下:

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");
		
		tx.commit();
		
	}catch(Exception e){
		e.printStackTrace();
		if(tx != null){
			tx.rollback();
		}
	}finally{
		HibernateUtils.closeSession(session);
	}
	
	//detached状态
}

查看上例运行结果视图:

    【Hibernate步步为营】--核心对象+持久对象全析(三)
        分析结果:session在提交事务的时候其实做了两部的操作,结合代码中的更新过程,首先是新增了一个User对象,之后执行了save操作,它会调用insert语句,然后在代码中做了一个setName的操作,重新修改了名称,但这时还没有同步到数据库中而是在内存中,这时就会有两种状态,我们称此时的数据位脏数据,最后提交事务的时候更新到数据库中。


结语

       本文针对持久对象的转化方法展开了详细的讨论,一个对象在整个生命周期中有三种状态。文章讨论至此,核心对象和持久对象的讨论已经完成,核心对象构成了Hibernate的内部运行机制,持久对象是关系模型和对象模型进行转化的核心。


【Hibernate步步为营】--核心对象+持久对象全析(三),布布扣,bubuko.com

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

上一篇:《A1 A Distributed In-Memory Graph Database》论文阅读


下一篇:Mysql 忘记密码