上篇文章讨论了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等方法。
调用save方法后进入的持久态。此时的为user对象加入了id标识:
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); } }
运行完毕后,查看数据库中信息,例如以下图:
结语
上文主要讨论分析了Hibernate持久对象在整个声明周期的状态转化过程,这几种状态的相互转化使得关系模型和对象模型进行了紧密的关联,另外在使用配置文件来管理这几种状态,这样使得Hibernate的操作简单。而且功能强大。上文仅仅是针对持久对象的几种状态做了初步的解析。另外还有状态之间的转化方法将会在下篇文章讨论。