当前位置: 移动技术网 > IT编程>开发语言>Java > 深入解析Java的Hibernate框架中的持久对象

深入解析Java的Hibernate框架中的持久对象

2019年07月22日  | 移动技术网IT编程  | 我要评论

一、持久对象生命周期
应用程序在使用hibernate框架后,创建的持久对象会经历一整套生命周期来完成数据库的操作,其中主要的三个状态分别是瞬态(transient)、持久化(persistent)、脱管(detached)。这三种状态的转换是能够在应用程序中控制的,如下图:

20167690714503.png (511×312)

为了能清楚的了解这几种状态,这里使用一个实例来查看下这几种状态下对象的不同,下面状态内的代码,具体步骤如下:
(1)创建hibernate_session程序集,并添加像相应的jar包;
(2)配置hibernate,添加相应的实体user类,及它的映射文件,并配置好相应的数据库连接;
user类文件的映射文件user.hbm.xml代码:

<?xml version="1.0"?> 
<!doctype hibernate-mapping public "-//hibernate/hibernate mapping dtd 3.0//en" 
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<!-- generated 2014-4-30 15:39:33 by hibernate tools 3.4.0.cr1 --> 
<hibernate-mapping> 
 <class name="com.hibernate.user"> 
  <id name="id"> 
   <generator class="uuid"/> 
  </id> 
  <property name="name"/> 
  <property name="password"/> 
  <property name="createtime"/> 
  <property name="expiretime"/> 
 </class> 
</hibernate-mapping> 

hibernate数据库连接配置代码:

<?xml version="1.0" encoding="utf-8"?> 
<!doctype hibernate-configuration public 
  "-//hibernate/hibernate configuration dtd 3.0//en" 
  "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
 <session-factory> 
  <property name="hibernate.connection.driver_class">com.mysql.jdbc.driver</property> 
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_session</property> 
  <property name="hibernate.connection.username">root</property> 
  <property name="hibernate.connection.password">ab12</property> 
  <!-- dialect:方言,封装的底层api,类似于runtime,将数据库转换为配置中的相应的语言 --> 
  <property name="hibernate.dialect">org.hibernate.dialect.mysqldialect</property> 
   
  <mapping resource="com/hibernate/user.hbm.xml"/> 
 </session-factory> 
</hibernate-configuration>

(3)添加静态成员sessionfactory的公共类,用来创建一个sessionfactory及其session对象;

package com.hibernate; 
 
import org.hibernate.session; 
import org.hibernate.sessionfactory; 
import org.hibernate.cfg.configuration; 
 
public class session { 
  
 private static sessionfactory factory; //声明静态局部变量sessionfactory,数据库镜像 
  
 static{ 
  try{ 
   //创建并获取配置数据库的配置文件,默认获取hibernate.cfg.xml 
   configuration cfg=new configuration().configure(); 
   factory=cfg.buildsessionfactory(); //构建一个数据库镜像 
  }catch(exception e){ 
   e.printstacktrace(); //打印错误信息 
  }   
 } 
  
 public static session getsession(){ 
  return factory.opensession(); //返回创建的session对象 
 } 
  
 public static sessionfactory getsessionfactory(){ 
  return factory; //返回相应的sessionfactory 
 } 
  
 //关闭session对象 
 public static void closesession(session session){ 
  if(session != null){ 
   if(session.isopen()){ 
    session.close(); 
   } 
  } 
 } 
} 

(4)添加一个source folder,并在该文件夹内添加名称为com.hibernate的package包,并在包中添加一个名称为sessiontest的类文件。

package com.hibernate; 
 
import java.util.date; 
 
import junit.framework.testcase; 
 
import org.hibernate.session; 
import org.hibernate.transaction; 
 
public class sessiontest extends testcase { 
 
} 

二、状态转化方法
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对象。            

20167690757908.png (814×218)

获取到了该对象,通过强制转换后得到了一个user对象。程序中添加了setname方法,也就是说会更新数据库中的名称,执行完成后检查数据库,如下图更新结果。     

20167690817755.png (812×203)

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对象如下图:

20167690836499.png (811×242)

分析上图,获取的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); 
  }   
} 

查看获取的结果图:

20167690857850.png (810×212)                    

分析结果图,代码中使用了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(); 

查看更新结果:

20167691051283.png (797×91)

分析更新结果,它其实更新了数据库的整行数据,这种更新操作有太多的不确定因素,不建议使用。

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状态 
} 

查看上例运行结果视图:

20167691108747.png (997×135)

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网