深入学习Hibernate持久化对象的三个状态

Hibernate中的对象有3中状态,瞬时对象(TransientObjects)、持久化对象(PersistentObjects)和离线对象(DetachedObjects也叫做脱管对象)。

下图3.1显示了瞬时对象、持久化对象和离线对象之间的关系以及它们之间的转换。

图3.1

临时状态:由Java的new命令开辟内存空间的java对象也就是普通的java对象,如果没有变量引用它它将会被JVM收回。临时对象在内存中是孤立存在的,它的意义是携带信息载体,不和数据库中的数据由任何的关联。通过Session的save()方法和saveOrUpdate()方法可以把一个临时对象和数据库相关联,并把临时对象携带的信息通过配置文件所做的映射插入数据库中,这个临时对象就成为持久化对象。

持久化状态:持久化对象在数据库中有相应的记录,持久化对象可以是刚被保存的,或者刚被加载的,但都是在相关联的session声明周期中保存这个状态。如果是直接数据库查询所返回的数据对象,则这些对象和数据库中的字段相关联,具有相同的id,它们马上变成持久化对象。如果一个临时对象被持久化对象引用,也立马变为持久化对象。
如果使用delete()方法,持久化对象变为临时对象,并且删除数据库中相应的记录,这个对象不再与数据库有任何的联系。

持久化对象总是与Session和Transaction关联在一起,在一个session中,对持久化对象的操作不会立即写到数据库,只有当Transaction(事务)结束时,才真正的对数据库更新,从而完成持久化对象和数据库的同步。在同步之前的持久化对象成为脏对象。

当一个session()执行close()、clear()、或evict()之后,持久化对象就变为离线对象,这时对象的id虽然拥有数据库的识别值,但已经不在Hibernate持久层的管理下,他和临时对象基本上一样的,只不过比临时对象多了数据库标识id。没有任何变量引用时,jvm将其回收。

脱管状态:Session关闭之后,与此Session关联的持久化对象就变成为脱管对象,可以继续对这个对象进行修改,如果脱管对象被重新关联到某个新的Session上,会在此转成持久对象。

脱管对象虽然拥有用户的标识id,所以通过update()、saveOrUpdate()等方法,再次与持久层关联。

下面我们就通过使用hibernate,实现对数据库的增删改查来体现三种状态之间的转换过程。

添加修改演示三种状态之间的变化

当我们建立Session都要实例化SessionFactory,所以我们把重复的代码进行封装,并且session是单线程的。我们把对session的管理,打开session,关闭session等封装到工具类中,代码如下所示。

package com.bjpowernode.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
 private static SessionFactory factory;
 //static只初始化一次.
 static
 {
 try{
 //默认读取的是hibernate.cfg.xml 文件.
 Configuration cfg = new Configuration().configure();
 //建立SessionFactory.
 factory = cfg.buildSessionFactory();
 }catch(Exception e )
 {
 e.printStackTrace();
 }
 }
 public static Session getSession()
 {
 //打开session.
 return factory.openSession();
 }
 //关闭session.
 public static void closeSession(Session session)
 {
 //判断是否为空.
 //判断是否是打开状态再进行关闭.
 if(session!=null)
 {
 if(session.isOpen())
 {
 session.close();
 }
 }
 }
 //返回工厂类.
 public static SessionFactory getSessionFactory()
 {
 return factory;
 }
} 

Hibernate.cfg.xml代码如下所示。

<!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">root</property>
 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 <property name="hibernate.show_sql">true</property>
 <mapping resource="com/bjpowernode/hibernate/User.hbm.xml"/>
 </session-factory>
</hibernate-configuration>

之前我们把对表添加的操作放到普通的java类中,在这个类的main()方法中执行,如果我们再对表进行其他的操作呢?那是不是还要建立新的java类,多个方法就不容易测试了。我们使用测试工具类JUnit来做测试,来测试增删改查。首先建立源目录,在test包中放测试程序。

我们建立我们的测试程序SessionTest.java,继承TestCase类,这样我们在SessionTest.java类中测试数据库中的某个方法,方法名的规范要以test开头。我们向User表中添加一条记录如下代码所示。

package com.bjpowernode.hibernate;
import java.util.Date;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class SessionTest extends TestCase {
 //测试方法以test开头.
 public void testSave1()
 {
 Session session = null;
 Transaction tx = null;
 try
 {
 //取得session.
 session = HibernateUtils.getSession();
 //自己开启事务. 返回 transient的一个实例.
 tx = session.beginTransaction();
 //传入值.变为Transient状态.
 User user = new User();
 user.setName("张三");
 user.setPassword("123");
 user.setCreateTime(new Date());
 user.setExpireTime(new Date());
 //进行保存.执行save则对session进行管理了. 处于持久状态.
 //persistent状态的对象.当对象的属性发生改变的时候,hibernate在清理
 //缓存的时候(脏数据检查)的时候,会和数据库同步.
 session.save(user);
 user.setName("李四");
 //再次提交.
 tx.commit();
 }catch(Exception e)
 {
 e.printStackTrace();
 if(tx!=null)
 {
 // 事务回滚.
 tx.rollback();
 }
 }finally
 {
 //关闭session.当关闭session时处于Detached状态.
 HibernateUtils.closeSession(session);
 }
 } 

首先是建立对象与表的会话session,开启事务session.beginTransaction(),实例化User对象,当我们User user = new User()的时候,当我们new一个对象的时候数据库是没有的,所以是Transient对象(临时对象),然后给user赋值,设置名称和密码以及其他属性。 为对象的所有属性赋值完毕,接下来保存到会话session中,拿到session执行save(user)方法。 当我们执行session的save()方法时,这个对象就被session管理了,session中有个map,会把对象放到map中,此时的对象我们就成为persistent状态(持久状态)。

接下来我们又把user中的name属性设置为“李四”,之后提交事务。我们先再会话中存储的“张三”,之后改为“李四”。try catch来扑捉异常,当执行完毕,关闭session后,对象处于detached状态(离线状态)。

我们创建数据库,利用ExportDB.java方法建立表。之后执行SessionTest的testSave1()方法,当执行到session方法的时候,表中自动生成user表的id值,并且名子为“张三”,之后再次执行,名字又变为“李四”,之后执行事务的commit()方法tx .commit ,此时控制台才发出语句,如下图3.2。

从控制台的语句中可以看出,显示发送的插入sql语句,后是update语句,首先是持久化对象user中的名字为“张三”,所以save的时候生成inset语句。此时user处于持久状态的对象,我们之后又给变了持久化对象,所以发送了一个修改语句。也就是当持久化对象发生修改时,我们再提交事务,就会把修改的全部体现出来(update语句)。
也就是我们再提交事务的时候,在清理缓存,也就是脏数据检查(内存中变了,而数据没变),要检查哪些数据是有问题的,要保持内存和数据库的同步。所以我们数据库中添加的记录,user的名字为李四(如图3.3所示)。

图3.3

如果上述代码中,我们在修改名字为李四后user.setName("李四");我们显示调用session的update()方法,session.update(),运行,会看到控制台上打印的sql语句和我们不加如session.update()打印的相同。持久化对象只要更改了,在提交事务的时候就会同步,没有必要再显示调用。

 Detached状态演示

我们在执行完所有的操作,关闭session后,此时的user对象变为detached状态,此时进行操作。

代码如下所示。

public void testSave3()
 {
 Session session = null;
 Transaction tx = null;
 User user = null;
 try
 {
  //取得session.
  session = HibernateUtils.getSession();
  //自己开启事务. fanhui transient的一个实例.
  tx = session.beginTransaction();
  //传入值.变为Transient状态.
  user = new User();
  user.setName("张三");
  user.setPassword("123");
  user.setCreateTime(new Date());
  user.setExpireTime(new Date());
  //进行保存.执行save则对session进行管理了. 处于持久状态.
  //persistent状态的对象.当对象的属性发生改变的时候,hibernate在清理
  //缓存的时候(脏数据检查)的时候,会和数据库同步.
  session.save(user);
  user.setName("李四");
  //可以显示的调用update方法,因为此时为持久状态,调用update没有什么意义.
  //再次提交.
  tx.commit();
 }catch(Exception e)
 {
  e.printStackTrace();
  if(tx!=null)
  {
  // 事务回滚.
  tx.rollback();
  }
 }finally
 {
  //关闭session.当关闭session时处于Detached状态.
  HibernateUtils.closeSession(session);
 }
 //已经不能用以前的session了.
 user.setName("王五");
 try
 {
  //得到新的session.
  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状态的user对象,改变这个对象的name值,user.setName("王五");之后我们再new一个新的

session,通过session开启事务,之后更新操作,session.update(user),也就是把离线的对象(或脱管对象)再纳入session管理,这样就会和数据库同步,因为session.update()就把user对象纳入session管理,user对象由离线状态变为persistent状态。

提交事务,将和数据库同步。把内存的改变体现到数据库上。控制台sql语句以及运行向表中添加记录结果如图3.4,3.5所示。

图3.4

总结

以上所述是小编给大家介绍的Hibernate持久化对象的三个状态,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 解析Java的Hibernate框架中的持久化类和映射文件

    持久化类 Hibernate的整个概念是采取从Java类属性的值,并将持久到数据库表.一个映射文件Hibernate的帮助确定如何从拉动类的值,并将它们映射与表和相关的域. 其对象或实例将存储在数据库表中的Java类在Hibernate中称为持久化类. Hibernate的效果最好,如果这些类遵循一些简单的规则,也称为普通Java对象(POJO)编程模型.有下列持久化类的主要规则,但是,这些规则并不是必需的. 将所有的持久化Java类需要一个默认的构造函数. 所有类应该包含为了让容易识别对象内H

  • 简介Java的Hibernate框架中的Session和持久化类

    Session Session对象用于获取与数据库的物理连接. Session对象是重量轻,设计了一个互动是需要与数据库每次被实例化.持久化对象被保存,并通过一个Session对象中检索. 会话中的对象不应该保持开放很长一段时间,因为他们通常不被线程安全的,他们应该被创建并根据需要摧毁他们.这次会议的主要功能是提供创建,读取和删除操作映射的实体类的实例.实例中可能存在以下三种状态之一在给定时间点: 短暂性: 持久化类的未与会话相关联,并在数据库中没有代表性,没有标识值的新实例被Hibernate

  • 深入学习Hibernate持久化对象的三个状态

    Hibernate中的对象有3中状态,瞬时对象(TransientObjects).持久化对象(PersistentObjects)和离线对象(DetachedObjects也叫做脱管对象). 下图3.1显示了瞬时对象.持久化对象和离线对象之间的关系以及它们之间的转换. 图3.1 临时状态:由Java的new命令开辟内存空间的java对象也就是普通的java对象,如果没有变量引用它它将会被JVM收回.临时对象在内存中是孤立存在的,它的意义是携带信息载体,不和数据库中的数据由任何的关联.通过Ses

  • 浅谈Java实体对象的三种状态以及转换关系

    最新的Hibernate文档中为Hibernate对象定义了四种状态(原来是三种状态,面试的时候基本上问的也是三种状态),分别是:瞬时态(new, or transient).持久态(managed, or persistent).游状态(detached)和移除态(removed,以前Hibernate文档中定义的三种状态中没有移除态),如下图所示,就以前的Hibernate文档中移除态被视为是瞬时态. 瞬时态:当new一个实体对象后,这个对象处于瞬时态,即这个对象只是一个保存临时数据的内存区

  • 浅谈hibernate中对象的3种状态_瞬时态、持久态、脱管态

    Hibernate的对象有3种状态,分别为:瞬时态(Transient). 持久态(Persistent).脱管态(Detached).处于持久态的对象也称为PO(Persistence Object),瞬时对象和脱管对象也称为VO(Value Object). • 瞬时态 由new命令开辟内存空间的java对象, eg. Person person = new Person("amigo", "女"); 如果没有变量对该对象进行引用,它将被java虚拟机回收. 瞬

  • Hibernate持久化对象生命周期原理解析

    三态的基本概念 1, 临时状态(Transient):也叫自由态,只存在于内存中,而在数据库中没有相应数据.用new创建的对象,它没有持久化,没有处于Session中,处于此状态的对象叫临时对象: 2, 持久化状态(Persistent):与session关联并且在数据库中有相应数据.已经持久化,加入到了Session缓存中.如通过hibernate语句保存的对象.处于此状态的对象叫持久对象: 3, 游离状态(Detached):持久化对象脱离了Session的对象.如Session缓存被清空的

  • Hibernate实体对象继承的三种方法

    Hibernate实体对象继承的方法 hibernate继承策略总共有三种,一种是共用一张表:一种是每个类一张表,表里面储存子类的信息和父类的信息:还有一种是通过表连接的方式,每个类都有一张表,但是子类对应的表只保存自己的信息,父类对应的表保存父类的信息,它们之间通过子类表和父类表的关联来获取所有的信息. 第一种方式,即共用一张表: @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(n

  • hibernate 三种状态的转换

    一.遇到的神奇的事情 使用jpa操作数据库,当我使用findAll()方法查处一个List的对象后,给对这个list的实体进行了一些操作,并没有调用update 或者 saveOrUpdate方法,更改后的数据却神奇的保存到数据库里面去了. 最后简单粗暴的解决办法是把这份从数据里面查出来的List  复制了一份,然后再操作,再返回.数据就正常了,数据库也没更新.后面找了资料才发现是jpa是对hibernate的封装,底层是hibernate,这是hibernate的持久状态搞的鬼. 二.hibe

  • 深入理解hibernate的三种状态

    学过hibernate的人都可能都知道hibernate有三种状态,transient(瞬时状态),persistent(持久化状态)以及detached(离线状态),大家伙也许也知道这三者之间的区别,比如瞬时状态就是刚new出来一个对象,还没有被保存到数据库中,持久化状态就是已经被保存到数据库中,离线状态就是数据库中有,但是session中不存在该对象.但是大家又是否对hibernate的session的那几个特殊方法一清二楚呢?或者说大家是否能够一眼就快速看出一个测试用例在反复的调用sess

  • Hibernate三种状态和Session常用的方法

    我们知道hibernate的核心就是对数据库的操作,里面的核心接口就是org.hibernate.Session接口.要想对数据库操作我们就要理清楚对象在整个操作中的所属的状态(Transient,Persistent,Detached).就像马士兵老师在视频中所说的,我们并不必死抠这些字眼,我们通过自己编写测试类就可以他们之间不同的区别. 其实三种状态各自的不必总结那么多,只是一个重要的地方就是Transient状态里面的对象是没有id的. session中常用的方法是save(),updat

  • Javascript学习笔记之 对象篇(四) : for in 循环

    先上范例: // Poisoning Object.prototype Object.prototype.bar = 1; var foo = {moo: 2}; for(var i in foo) { console.log(i); // prints both bar and moo } 这里我们要注意两点,一是 for in 循环会忽略 enumerable 设置为 false 的属性.例如一个数组的 length 属性.第二是,由于 for in 会遍历整个原型链,所以当原型链过长时,会

  • Java反射之类的实例对象的三种表示方式总结

    如下所示: <span style="font-size:14px;">package com.imooc.reflect; public class ClassDemo1 { public static void main(String[] args) { //Foo的实例对象如何表示 Foo foo1 = new Foo();//foo1就表示出来了 //Foo这个类,也是一个实例对象,Class类的实例对象,如何表示呢. //任何一个类都是Class的实例对象,这个实

随机推荐