zoukankan      html  css  js  c++  java
  • 持久化对象的状态转换


     看图便知道,通常情况下,大家都认为session中的对象存在三种状态:瞬时(transitent)、持久化(persistent)以及

    托管(detached)。不过有时还存一种观点,认为应该是四种状态,即还存在一种移除(removed)状态。对于这两种观点呢我们暂不追究到底以哪个为依据,因为到现在还没统一的定论

      本篇文章中,为了全面讲解,所以移除状态我也也涉及到

      Session中对象的状态
     1) 瞬时状态(transient): 新创建的对象。没有和某个Session进行关联。没有对象标识符(OID)。
     2) 持久化状态(persistent): 与某个session进行关联。有对象标识符。数据库表中有对应的记录。
        session在清理缓存时,会把此对象的数据与数据库表的数据进行同步。
     3) 脱管状态(detached): 脱离了Session的管理。有对象标识符。数据库表中有对应的记录。
              不保证此对象的数据与数据库表的数据是否同步。
     4) 移除状态(removed): 与某个session进行关联。有对象标识符,数据库表中有对应的记录。
        session在清理缓存时,会把数据库表对应的记录删除掉。这个对象不能再去使用它.

    针对这些解释呢,基于第一篇文章中的类和配置文件,这里只提供一个测试类,方法上都有更详细的解释

    Java代码 复制代码
    1. <SPAN style="FONT-SIZE: medium"><SPAN style="FONT-SIZE: large">package com.javacrazyer.test;   
    2.   
    3.  import org.hibernate.Session;    
    4.  import org.hibernate.SessionFactory;    
    5.  import org.hibernate.Transaction;    
    6.  import org.junit.BeforeClass;    
    7.  import org.junit.Test;    
    8.   
    9.  import com.javacrazyer.common.HibernateUtil;    
    10.  import com.javacrazyer.domain.Student;    
    11.   
    12.  /**   
    13.  * 使用Hibernate API完成CRUD 更复杂的持久化操作需要使用到Query接口  
    14.  *   
    15.  */  
    16.  public class HibernateTest {    
    17.   
    18.     private static SessionFactory factory;    
    19.   
    20.     @BeforeClass   
    21.     public static void init() {    
    22.         factory = HibernateUtil.getSessionFactory();   
    23.     }   
    24.   
    25.     @Test   
    26.     public void testSessionCache() {    
    27.         Session session = factory.openSession();   
    28.         Transaction tx = session.beginTransaction();   
    29.   
    30.         Student stu = (Student) session.get(Student.class1);    
    31.         System.out.println(stu);   
    32.   
    33.         Student stu2 = (Student) session.get(Student.class1);    
    34.         System.out.println(stu2);   
    35.   
    36.         stu2.setName("xkk");    
    37.         System.out.println(stu2);   
    38.         /*flush()将数据库与缓存中的数据同步,不是必须调用的*/   
    39.         session.flush(); // 手动清理缓存   
    40.        
    41.         /*  
    42.          * clear()写在flush后面,执行后才会引起缓存数据变化,session.flush()的调用牵扯到事务,  
    43.          * 首先我们知道在执行事务之前都会将AutoCommit设置为false【手动提交方式,因为默认是true  
    44.          * 自动提交的】 当AutoCommit 为false时我们执行完事务就要调用到session.flush();  
    45.          * session.clear();一切处理完后我们要close掉当前的这个session  
    46.          */  
    47.         session.clear();   
    48.   
    49.         stu2.setScore(77.00);   
    50.         System.out.println(stu2);   
    51.   
    52.         tx.commit();   
    53.         session.close();   
    54.     }   
    55.   
    56.     @Test  
    57.     public void testObjectStatus() {   
    58.         Student stu = new Student(); // transient瞬时状态   
    59.         stu.setName("ww");   
    60.         stu.setGender(false);   
    61.         stu.setAge(38);   
    62.         stu.setScore(65.5);   
    63.   
    64.         Session session = factory.openSession();   
    65.         Transaction tx = session.beginTransaction();   
    66.   
    67.         session.save(stu); // persistent持久化状态   
    68.         System.out.println(stu);   
    69.   
    70.         tx.commit();   
    71.         session.close();   
    72.   
    73.         System.out.println(stu); // detached 脱管   
    74.   
    75.         Session session2 = factory.openSession();   
    76.         session2.beginTransaction();   
    77.   
    78.         session2.save(stu);   
    79.         System.out.println(stu);// 脱管状态--> 持久化状态 (不建议用save方法来操作脱管对象)   
    80.   
    81.         session2.getTransaction().commit();   
    82.         session2.close();   
    83.     }   
    84.   
    85.     /*  
    86.      * get()方法:先查找session缓存中是否已经存在此标识符指定的对象,如果存在,直接使用.  
    87.      * 否则发出SQL语句从数据库中获取.如果数据库中也不存在,返回null  
    88.      */  
    89.     @Test  
    90.     public void testGet() {   
    91.   
    92.         Session session = factory.openSession();   
    93.         session.beginTransaction();   
    94.   
    95.         Student stu = (Student) session.get(Student.class1);   
    96.   
    97.         System.out.println(stu);   
    98.   
    99.         session.getTransaction().commit();   
    100.         session.close();   
    101.     }   
    102.   
    103.     /*  
    104.      * load()方法先查找session缓存中是否已经存在此标识符指定的对象,如果存在,直接使用.  
    105.      * 否则Hibernate会为此标识符对象产生一个代理对象,实现延迟加载(懒加载)的功能。这个代理对象包含有OID。  
    106.      * 当要使用到此对象的非OID属性值,才发出SQL语句去数据库中获取。  
    107.      * 如果数据库中也不存在,返回InvocationTargetException异常。  
    108.      */  
    109.     @Test  
    110.     public void testLoad() {   
    111.         Session session = factory.openSession();   
    112.         session.beginTransaction();   
    113.   
    114.         Student stu = (Student) session.load(Student.class5);   
    115.   
    116.         System.out.println(stu.getId());   
    117.   
    118.         System.out.println(stu);   
    119.   
    120.         session.getTransaction().commit();   
    121.         session.close();   
    122.     }   
    123.   
    124.     /*  
    125.      * delete()方法:持久化状态 --> 移除状态 .  
    126.      *  注意:处理移除状态的对象不要再去使用它,因为,在session清理缓存时,数据库表中对应的数据会被删除掉.  
    127.      */  
    128.     @Test  
    129.     public void testDelete() {   
    130.   
    131.         Session session = factory.openSession();   
    132.         session.beginTransaction();   
    133.   
    134.         Student stu = (Student) session.load(Student.class7);   
    135.   
    136.         session.delete(stu);   
    137.   
    138.         System.out.println(stu);   
    139.   
    140.         session.getTransaction().commit();   
    141.         session.close();   
    142.   
    143.         System.out.println(stu);   
    144.     }   
    145.   
    146.     @Test  
    147.     /* update()方法: 重附被修改的脱管对象,成为持久化对象 */  
    148.     public void testUpdate() {   
    149.         Session session = factory.openSession();   
    150.         session.beginTransaction();   
    151.   
    152.         Student stu = (Student) session.load(Student.class8);   
    153.   
    154.         stu.setName("更新持久化状态的对象");   
    155.   
    156.         session.getTransaction().commit();   
    157.         session.close();   
    158.   
    159.         System.out.println(stu);   
    160.         stu.setName("修改脱管对象");   
    161.   
    162.         Session session2 = factory.openSession();   
    163.         session2.beginTransaction();   
    164.         session2.update(stu);   
    165.         session2.getTransaction().commit();   
    166.         session2.close();   
    167.     }   
    168.   
    169.     @Test  
    170.     /*  
    171.      * saveOrUpdate()方法:   
    172.      * 1) 瞬时对象,执行类似save()的功能   
    173.      * 2) 脱管对象,如果在当前session缓存中不存在同OID的对象,就执行类似update()的功能。否则,抛出异常。  
    174.      */  
    175.     public void testSaveOrUpdate() {   
    176.   
    177.         Session session = factory.openSession();   
    178.         session.beginTransaction();   
    179.   
    180.         Student stu = (Student) session.get(Student.class9);   
    181.   
    182.         System.out.println(stu);   
    183.   
    184.         session.getTransaction().commit();   
    185.         session.close();   
    186.   
    187.         // 处理脱管状态   
    188.         stu.setName("9哥");   
    189.   
    190.         Session session2 = factory.openSession();   
    191.         session2.beginTransaction();   
    192.   
    193.         session2.saveOrUpdate(stu);   
    194.         System.out.println(stu);   
    195.   
    196.         session2.getTransaction().commit();   
    197.         session2.close();   
    198.   
    199.         System.out.println(stu);   
    200.     }   
    201.   
    202.     @Test  
    203.     public void testSaveOrUpdate2() {   
    204.   
    205.         Student stu = new Student();   
    206.         stu.setId(19); // 对象没有与session关联,并且OID有值,就被认为是脱管对象   
    207.   
    208.         Session session = factory.openSession();   
    209.         session.beginTransaction();   
    210.   
    211.         session.saveOrUpdate(stu);   
    212.   
    213.         session.getTransaction().commit();   
    214.         session.close();   
    215.     }   
    216.   
    217.     @Test  
    218.     public void testSaveOrUpdate3() {   
    219.         Student stu = new Student();   
    220.         stu.setId(9); // 对象没有与session关联,并且OID有值,就被认为是脱管对象   
    221.         stu.setName("su");   
    222.   
    223.         Session session = factory.openSession();   
    224.         session.beginTransaction();   
    225.   
    226.         session.get(Student.class9);   
    227.   
    228.         session.saveOrUpdate(stu);   
    229.   
    230.         session.getTransaction().commit();   
    231.         session.close();   
    232.     }   
    233.   
    234.     @Test  
    235.     /*  
    236.      * merge()方法:  
    237.      * 1) 瞬时对象,执行类似save()的功能  
    238.      * 2)脱管对象:如果在当前session缓存中不存在同OID的对象,就执行类似update()的功能。  
    239.      * 否则,把传入的对象数据合并到缓存中的对象,返回缓存中的对象。   
    240.      * 3) 经常用来替代update()和saveOrUpdate()方法。  
    241.      */  
    242.     public void testmerge() {   
    243.         Student stu = new Student();   
    244.         stu.setId(9); // 对象没有与session关联,并且OID有值,就被认为是脱管对象   
    245.         stu.setName("su");   
    246.   
    247.         Session session = factory.openSession();   
    248.         session.beginTransaction();   
    249.   
    250.         session.get(Student.class9);   
    251.   
    252.         stu = (Student) session.merge(stu);   
    253.   
    254.         session.getTransaction().commit();   
    255.         session.close();   
    256.     }   
    257.   
    258. }</SPAN></SPAN>  
    package com.javacrazyer.test;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.junit.BeforeClass;
    import org.junit.Test;
    
    import com.javacrazyer.common.HibernateUtil;
    import com.javacrazyer.domain.Student;
    
    /**
     * 使用Hibernate API完成CRUD 更复杂的持久化操作需要使用到Query接口
     * 
     */
    public class HibernateTest {
    
    	private static SessionFactory factory;
    
    	@BeforeClass
    	public static void init() {
    		factory = HibernateUtil.getSessionFactory();
    	}
    
    	@Test
    	public void testSessionCache() {
    		Session session = factory.openSession();
    		Transaction tx = session.beginTransaction();
    
    		Student stu = (Student) session.get(Student.class, 1);
    		System.out.println(stu);
    
    		Student stu2 = (Student) session.get(Student.class, 1);
    		System.out.println(stu2);
    
    		stu2.setName("xkk");
    		System.out.println(stu2);
    		/*flush()将数据库与缓存中的数据同步,不是必须调用的*/
    		session.flush(); // 手动清理缓存
    	
    		/*
    		 * clear()写在flush后面,执行后才会引起缓存数据变化,session.flush()的调用牵扯到事务,
    		 * 首先我们知道在执行事务之前都会将AutoCommit设置为false【手动提交方式,因为默认是true
    		 * 自动提交的】 当AutoCommit 为false时我们执行完事务就要调用到session.flush();
    		 * session.clear();一切处理完后我们要close掉当前的这个session
    		 */
    		session.clear();
    
    		stu2.setScore(77.00);
    		System.out.println(stu2);
    
    		tx.commit();
    		session.close();
    	}
    
    	@Test
    	public void testObjectStatus() {
    		Student stu = new Student(); // transient瞬时状态
    		stu.setName("ww");
    		stu.setGender(false);
    		stu.setAge(38);
    		stu.setScore(65.5);
    
    		Session session = factory.openSession();
    		Transaction tx = session.beginTransaction();
    
    		session.save(stu); // persistent持久化状态
    		System.out.println(stu);
    
    		tx.commit();
    		session.close();
    
    		System.out.println(stu); // detached 脱管
    
    		Session session2 = factory.openSession();
    		session2.beginTransaction();
    
    		session2.save(stu);
    		System.out.println(stu);// 脱管状态--> 持久化状态 (不建议用save方法来操作脱管对象)
    
    		session2.getTransaction().commit();
    		session2.close();
    	}
    
    	/*
    	 * get()方法:先查找session缓存中是否已经存在此标识符指定的对象,如果存在,直接使用.
    	 * 否则发出SQL语句从数据库中获取.如果数据库中也不存在,返回null
    	 */
    	@Test
    	public void testGet() {
    
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		Student stu = (Student) session.get(Student.class, 1);
    
    		System.out.println(stu);
    
    		session.getTransaction().commit();
    		session.close();
    	}
    
    	/*
    	 * load()方法先查找session缓存中是否已经存在此标识符指定的对象,如果存在,直接使用.
    	 * 否则Hibernate会为此标识符对象产生一个代理对象,实现延迟加载(懒加载)的功能。这个代理对象包含有OID。
    	 * 当要使用到此对象的非OID属性值,才发出SQL语句去数据库中获取。
    	 * 如果数据库中也不存在,返回InvocationTargetException异常。
    	 */
    	@Test
    	public void testLoad() {
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		Student stu = (Student) session.load(Student.class, 5);
    
    		System.out.println(stu.getId());
    
    		System.out.println(stu);
    
    		session.getTransaction().commit();
    		session.close();
    	}
    
    	/*
    	 * delete()方法:持久化状态 --> 移除状态 .
    	 *  注意:处理移除状态的对象不要再去使用它,因为,在session清理缓存时,数据库表中对应的数据会被删除掉.
    	 */
    	@Test
    	public void testDelete() {
    
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		Student stu = (Student) session.load(Student.class, 7);
    
    		session.delete(stu);
    
    		System.out.println(stu);
    
    		session.getTransaction().commit();
    		session.close();
    
    		System.out.println(stu);
    	}
    
    	@Test
    	/* update()方法: 重附被修改的脱管对象,成为持久化对象 */
    	public void testUpdate() {
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		Student stu = (Student) session.load(Student.class, 8);
    
    		stu.setName("更新持久化状态的对象");
    
    		session.getTransaction().commit();
    		session.close();
    
    		System.out.println(stu);
    		stu.setName("修改脱管对象");
    
    		Session session2 = factory.openSession();
    		session2.beginTransaction();
    		session2.update(stu);
    		session2.getTransaction().commit();
    		session2.close();
    	}
    
    	@Test
    	/*
    	 * saveOrUpdate()方法: 
    	 * 1) 瞬时对象,执行类似save()的功能 
    	 * 2) 脱管对象,如果在当前session缓存中不存在同OID的对象,就执行类似update()的功能。否则,抛出异常。
    	 */
    	public void testSaveOrUpdate() {
    
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		Student stu = (Student) session.get(Student.class, 9);
    
    		System.out.println(stu);
    
    		session.getTransaction().commit();
    		session.close();
    
    		// 处理脱管状态
    		stu.setName("9哥");
    
    		Session session2 = factory.openSession();
    		session2.beginTransaction();
    
    		session2.saveOrUpdate(stu);
    		System.out.println(stu);
    
    		session2.getTransaction().commit();
    		session2.close();
    
    		System.out.println(stu);
    	}
    
    	@Test
    	public void testSaveOrUpdate2() {
    
    		Student stu = new Student();
    		stu.setId(19); // 对象没有与session关联,并且OID有值,就被认为是脱管对象
    
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		session.saveOrUpdate(stu);
    
    		session.getTransaction().commit();
    		session.close();
    	}
    
    	@Test
    	public void testSaveOrUpdate3() {
    		Student stu = new Student();
    		stu.setId(9); // 对象没有与session关联,并且OID有值,就被认为是脱管对象
    		stu.setName("su");
    
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		session.get(Student.class, 9);
    
    		session.saveOrUpdate(stu);
    
    		session.getTransaction().commit();
    		session.close();
    	}
    
    	@Test
    	/*
    	 * merge()方法:
    	 * 1) 瞬时对象,执行类似save()的功能
    	 * 2)脱管对象:如果在当前session缓存中不存在同OID的对象,就执行类似update()的功能。
    	 * 否则,把传入的对象数据合并到缓存中的对象,返回缓存中的对象。 
    	 * 3) 经常用来替代update()和saveOrUpdate()方法。
    	 */
    	public void testmerge() {
    		Student stu = new Student();
    		stu.setId(9); // 对象没有与session关联,并且OID有值,就被认为是脱管对象
    		stu.setName("su");
    
    		Session session = factory.openSession();
    		session.beginTransaction();
    
    		session.get(Student.class, 9);
    
    		stu = (Student) session.merge(stu);
    
    		session.getTransaction().commit();
    		session.close();
    	}
    
    }

     

    补充说明:sessionFactory.getCurrentSession()和sessionFactory.openSesion()的区别介绍


      1. 如果使用的是getCurrentSession来创建session的话,在commit后,session就自动被关闭了,也就是不用再session.close()了。但是如果使用的是openSession方法创建的session的话,那么必须显示的关闭session,也就是调用session.close()方法。这样commit后,session并没有关闭


     2.
    getCurrentSession创建的session会和绑定到当前线程,而openSession不会。getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭, 


     3.  使用SessionFactory.getCurrentSession()需要在hibernate.cfg.xml中如下配置:
      * 如果采用jdbc独立引用程(本地事务:JDBC事务)序配置如下:
        <property name="hibernate.current_session_context_class">thread</property>
      * 如果采用了JTA事务配置(全局事务:JTA事务)如下 
        <property name="hibernate.current_session_context_class">jta</property>


    4.getCurrentSession () 使用当前的session 

    openSession() 重新建立一个新的session 



    总结:

     getCurrentSession和openSession无论是那种方式,如果是纯JDBC项目的话,那你必须手动写上事务的开启和提交,openSession事务提交后还得手动写session.close()关闭,尽管是这样也不一定真的关了;getCurrentSession提交事务后会自动关闭session所以不用手动写session.close()

     其实际项目(我指的是SSH项目)中由于在Spring中配置有事务管理,所以我们用getCurrentSession时手动写的关于事务的代码配置都不用写了

    Java代码 复制代码
    1. <SPAN style="FONT-SIZE: large">//openSession()方法的测试,必须在事务提交后关闭session   
    2. @Test  
    3.     public void openSessionDelete(){   
    4.         Session session = factory.openSession();   
    5.         Transaction tx = session.beginTransaction();   
    6.         Student stu = (Student) session.get(Student.class1);   
    7.         session.delete(stu);   
    8.         tx.commit();   
    9.         session.close();   
    10.     }   
    11. //getCurrentSession()方法,不需要关闭session   
    12.     @Test  
    13.     public void getCurrentSessionDelete(){   
    14.             Session session = factory.getCurrentSession();   
    15.             Transaction tx = session.beginTransaction();   
    16.             Student stu = (Student) session.get(Student.class,2);   
    17.             session.delete(stu);   
    18.             tx.commit();   
    19.     }</SPAN>  
    //openSession()方法的测试,必须在事务提交后关闭session
    @Test
        public void openSessionDelete(){
        	Session session = factory.openSession();
        	Transaction tx = session.beginTransaction();
        	Student stu = (Student) session.get(Student.class, 1);
        	session.delete(stu);
        	tx.commit();
         	session.close();
        }
    //getCurrentSession()方法,不需要关闭session
    	@Test
    	public void getCurrentSessionDelete(){
    	    	Session session = factory.getCurrentSession();
    	    	Transaction tx = session.beginTransaction();
    	    	Student stu = (Student) session.get(Student.class,2);
    	    	session.delete(stu);
    	    	tx.commit();
    	}
     

    相比之下getCurrentSession()还是最适合的


    这句红色标记的话我要用下面的话来解释下:


        在一个应用程序中,如果DAO 层使用Spring 的hibernate 模板,通过Spring 来控制session 的生命周期,则首选getCurrentSession ()。 

    使用Hibernate的大多数应用程序需要某种形式的“上下文相关的” session,特定的session在整个特定的上下文范围内始终有效。然而,对不同类型的应用程序而言,要为什么是组成这种“上下文”下一个定义通常是困难的;不同的上下文对“当前”这个概念定义了不同的范围。在3.0版本之前,使用Hibernate的程序要么采用自行编写的基于 ThreadLocal的上下文session,要么采用HibernateUtil这样的辅助类,要么采用第三方框架(比如Spring或Pico),它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关session。 


        从3.0.1版本开始,Hibernate增加了SessionFactory.getCurrentSession()方法。一开始,它假定了采用JTA事务,JTA事务定义了当前session的范围和上下文(scope and context)。Hibernate开发团队坚信,因为有好几个独立的JTA TransactionManager实现稳定可用,不论是否被部署到一个J2EE容器中,大多数(假若不是所有的)应用程序都应该采用JTA事务管理。基于这一点,采用JTA的上下文相关session可以满足一切需要。 

        在 SessionFactory 启动的时候, Hibernate 会根据配置创建相应的 CurrentSessionContext ,在 getCurrentSession() 被调用的时候,实际被执行的方法是 CurrentSessionContext.currentSession() 。在 currentSession() 执行时,如果当前 Session 为空, currentSession 会调用 SessionFactory 的 openSession 。所以 getCurrentSession() 对于 Java EE 来说是更好的获取Session 的方法。 

        

        那么跟跟openSession相比,getCurrentSession在使用上有什么注意的呢? 到现在发现的一个就是,由于getCurrentSession方法返回的session在做事务的commit时, session可能会自动给关掉,这样若自己的代码中再调用session.close时就抛出了"Session was already closed"异常。 


    在HB3.X 版本中提供了一个getCurrentSession() 这个方法,这个方法和早期使用的openSession() 是有区别的。

    openSession() ,表示创建了一个新的session 对象,当你使用完了以后就要必须调用close 方法来关闭当前的session 。getCurrentSession() ,总是会返回“ 当前的” 工作单元。Session 在第一次被使用的时候,即第一次调用getCurrentSession() 的时候,其生命周期就开始。然后她被Hibernate 绑定到当前线程。当事物结束的时候,不管是提交还是回滚,Hibernate 会自动把Session 从当前线程剥离,并且关闭。若在次调用getCurrentSession() ,会得到一个新的Session, 并且开始一个新的工作单元。这是Hibernate 最广泛的thread-bound model ,支持代码灵活分层( 事物划分和数据访问代码的分离) 

  • 相关阅读:
    百度富文本编辑器的上传图片的路径问题
    laravel初次学习总结及一些细节
    macOS apache配置及开启虚拟服务器的开启,apache开启重写模式
    类似于qq空间类型的评论和回复
    向php提交数据及json
    mac 初次配置apache,及mac下安装mysql
    C#连接mysql数据库插入数据后获取自增长主键ID值
    PHP 真正多线程的使用
    C# 连接mysql数据库
    MySql状态查看方法 MySql如何查看连接数和状态?
  • 原文地址:https://www.cnblogs.com/jinzhengquan/p/1957447.html
Copyright © 2011-2022 走看看