Hibernate旅程(三)Hibernate持久化对象的三个状态

 

 版权声明:本文为博主原创文章,转载请标明出处。 https://blog.****.net/lovesummerforever/article/details/19171571

 

 

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

 

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

 

Hibernate旅程(三)Hibernate持久化对象的三个状态

3.1

 

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

 

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

如果使用delete()方法,持久化对象变为临时对象,并且删除数据库中相应的记录,这个对象不再与数据库有任何的联系。

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

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

 

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

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

 

 

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

 

 

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

 

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

 

 
  1. package com.bjpowernode.hibernate;

  2.  
  3. import org.hibernate.Session;

  4. import org.hibernate.SessionFactory;

  5. import org.hibernate.cfg.Configuration;

  6.  
  7. public class HibernateUtils {

  8.  
  9. private static SessionFactory factory;

  10.  
  11. //static只初始化一次.

  12. static

  13. {

  14. try{

  15. //默认读取的是hibernate.cfg.xml 文件.

  16. Configuration cfg = new Configuration().configure();

  17.  
  18. //建立SessionFactory.

  19. factory = cfg.buildSessionFactory();

  20.  
  21. }catch(Exception e )

  22. {

  23. e.printStackTrace();

  24. }

  25. }

  26.  
  27. public static Session getSession()

  28. {

  29. //打开session.

  30. return factory.openSession();

  31. }

  32.  
  33. //关闭session.

  34. public static void closeSession(Session session)

  35. {

  36. //判断是否为空.

  37. //判断是否是打开状态再进行关闭.

  38.  
  39. if(session!=null)

  40. {

  41. if(session.isOpen())

  42. {

  43. session.close();

  44. }

  45. }

  46. }

  47.  
  48. //返回工厂类.

  49. public static SessionFactory getSessionFactory()

  50. {

  51. return factory;

  52. }

  53. }

  54.  


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

 

 

 
  1. <!DOCTYPE hibernate-configuration PUBLIC

  2. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

  3. "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

  4.  
  5. <hibernate-configuration>

  6. <session-factory >

  7. <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

  8.  
  9. <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/Hibernate_session</property>

  10.  
  11. <property name="hibernate.connection.username">root</property>

  12. <property name="hibernate.connection.password">root</property>

  13.  
  14. <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

  15.  
  16. <property name="hibernate.show_sql">true</property>

  17.  
  18. <mapping resource="com/bjpowernode/hibernate/User.hbm.xml"/>

  19. </session-factory>

  20. </hibernate-configuration>


   

 

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

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

 

 
  1. package com.bjpowernode.hibernate;

  2.  
  3. import java.util.Date;

  4.  
  5. import junit.framework.TestCase;

  6.  
  7. import org.hibernate.Session;

  8. import org.hibernate.Transaction;

  9.  
  10. public class SessionTest extends TestCase {

  11.  
  12. //测试方法以test开头.

  13. public void testSave1()

  14. {

  15. Session session = null;

  16. Transaction tx = null;

  17. try

  18. {

  19. //取得session.

  20. session = HibernateUtils.getSession();

  21. //自己开启事务. 返回 transient的一个实例.

  22. tx = session.beginTransaction();

  23.  
  24. //传入值.变为Transient状态.

  25. User user = new User();

  26. user.setName("张三");

  27. user.setPassword("123");

  28. user.setCreateTime(new Date());

  29. user.setExpireTime(new Date());

  30.  
  31. //进行保存.执行save则对session进行管理了. 处于持久状态.

  32. //persistent状态的对象.当对象的属性发生改变的时候,hibernate在清理

  33. //缓存的时候(脏数据检查)的时候,会和数据库同步.

  34. session.save(user);

  35. user.setName("李四");

  36. //再次提交.

  37. tx.commit();

  38. }catch(Exception e)

  39. {

  40. e.printStackTrace();

  41. if(tx!=null)

  42. {

  43. // 事务回滚.

  44. tx.rollback();

  45. }

  46. }finally

  47. {

  48. //关闭session.当关闭session时处于Detached状态.

  49. HibernateUtils.closeSession(session);

  50. }

  51.  
  52. }

 

 


     首先是建立对象与表的会话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。

Hibernate旅程(三)Hibernate持久化对象的三个状态

 

 从控制台的语句中可以看出,显示发送的插入sql语句,后是update语句,首先是持久化对象user中的名字为“张三”,所以save的时候生成inset语句。此时user处于持久状态的对象,我们之后又给变了持久化对象,所以发送了一个修改语句。也就是当持久化对象发生修改时,我们再提交事务,就会把修改的全部体现出来(update语句)。

也就是我们再提交事务的时候,在清理缓存,也就是脏数据检查(内存中变了,而数据没变),要检查哪些数据是有问题的,要保持内存和数据库的同步。所以我们数据库中添加的记录,user的名字为李四(如图3.3所示)。

Hibernate旅程(三)Hibernate持久化对象的三个状态

图3.3

 

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

 Detached状态演示

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

代码如下所示。

 

 
  1. public void testSave3()

  2. {

  3. Session session = null;

  4. Transaction tx = null;

  5.  
  6. User user = null;

  7. try

  8. {

  9. //取得session.

  10. session = HibernateUtils.getSession();

  11. //自己开启事务. fanhui transient的一个实例.

  12. tx = session.beginTransaction();

  13.  
  14. //传入值.变为Transient状态.

  15. user = new User();

  16. user.setName("张三");

  17. user.setPassword("123");

  18. user.setCreateTime(new Date());

  19. user.setExpireTime(new Date());

  20.  
  21. //进行保存.执行save则对session进行管理了. 处于持久状态.

  22. //persistent状态的对象.当对象的属性发生改变的时候,hibernate在清理

  23. //缓存的时候(脏数据检查)的时候,会和数据库同步.

  24. session.save(user);

  25.  
  26. user.setName("李四");

  27. //可以显示的调用update方法,因为此时为持久状态,调用update没有什么意义.

  28. //再次提交.

  29. tx.commit();

  30. }catch(Exception e)

  31. {

  32. e.printStackTrace();

  33. if(tx!=null)

  34. {

  35. // 事务回滚.

  36. tx.rollback();

  37. }

  38. }finally

  39. {

  40. //关闭session.当关闭session时处于Detached状态.

  41. HibernateUtils.closeSession(session);

  42. }

  43.  
  44. //已经不能用以前的session了.

  45. user.setName("王五");

  46. try

  47. {

  48. //得到新的session.

  49. session = HibernateUtils.getSession();

  50. //开启事务.

  51. session.beginTransaction();

  52. //将detached状态的对象重新纳入session管理.

  53. //此时将变为persistent状态的对象.

  54. //persistent状态的对象,在清理缓存时,会根数据库同步.

  55. session.update(user);

  56. //提交事务.把内存的改变提交到数据库上.

  57. session.getTransaction().commit();

  58. }catch(Exception e)

  59. {

  60. e.printStackTrace();

  61. session.getTransaction().rollback();

  62. }finally

  63. {

  64. HibernateUtils.closeSession(session);

  65. }

  66.  
  67. }


    

 

  取得detached状态的user对象,改变这个对象的name值,user.setName("王五");之后我们再new一个新的session,通过session开启事务,之后更新操作,session.update(user),也就是把离线的对象(或脱管对象)再纳入session管理,这样就会和数据库同步,因为session.update()就把user对象纳入session管理,user对象由离线状态变为persistent状态。

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

Hibernate旅程(三)Hibernate持久化对象的三个状态

图3.4

Hibernate旅程(三)Hibernate持久化对象的三个状态

图3.5