第二節 hibernate session介紹以及session常用方法介紹


原創地址:http://www.cnblogs.com/binyulan/p/5628579.html  

 

  Session是java應用程序和hibernate框架之間的一個主要接口。它是從持久化服務中剝離出來的一個非常重要的API接口。

  Session的主要功能是為映射的實體類的實例提供增刪改查操作(User.class 為被映射的實體類,new User()即為實例)。這些實例可能是以下三種狀態之一:

  1) transient: 從沒有被持久化,不在Session緩存中
  2) persistent: 在Session的緩存中。
  3) detached: 曾經是persistent狀態,現在不在Session緩存中。

  transient 實例通過調用save(), persist() or saveOrUpdate()可以變成persistent實例。persistent實例通過調用delete可以變成transient實例。任何通過get()或者load()方法獲取的實例都是persistent實例。detached實例通過調用update(), saveOrUpdate(), lock() or replicate()可以變成persistent實例。transient或者detached實例通過調用merge()方法可以生成一個新的persistent實例,但是並不是他們自己,這個persistent實例是merge方法自己創建的。

  save() 和 persist() 生成SQL insert。delete() 生成SQL delete。update() 和 merge()生成SQL update。對persistent實例的修改在flush時會生成SQL update。saveOrUpdate() 和 replicate()生成insert或者update。

  Session接口的實現類並沒有專門設計為線程安全的。相反,每個線程或者事務都應該通過SessionFactory獲取自己的實例。

  一個典型的事務應該使用如下的形式:

 Session sess = factory.openSession();
 Transaction tx;
 try {
     tx = sess.beginTransaction();
     //do some work
     ...
     tx.commit();
 }
 catch (Exception e) {
     if (tx!=null) tx.rollback();
     throw e;
 }
 finally {
     sess.close();
 }

  如果Session拋出異常,事務必須回滾。同時Session被棄用,因為Session內部狀態和數據庫可能會不一致。

1 保存對象到數據庫 session.save(Object user); //參數user為transient實例,返回值為新生成的主鍵id

持久化transient實例。返回值為生成的主鍵id。

按照第一節的配置,主鍵的生成策略為native(數據庫自動生成主鍵),由於數據庫使用的是mysql 5,所以是自增的主鍵生成方式。保存對象時並不需要設置id屬性。

    @Test
    public void testSave() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan");
            session.save(user);
        } catch (HibernateException e) {
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

2 保存對象到數據庫 session.persist(Object user); //參數user為transient實例

持久化transient實例。這個方法和session.save()方法一樣,都是保存對象到數據庫。但是不能設置id屬性,否則拋出異常。

    @Test
    public void testPersist() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan");
            user.setId(13);
            session.persist(user);
        } catch (HibernateException e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

 執行testPersist后拋出異常,如下:

org.hibernate.PersistentObjectException: detached entity passed to persist: com.binyulan.domain.User
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)

user創建出來為transient實例,但是異常顯示是detached實例。所以我認為只要給對象設置了id屬性,即使沒有持久化過,也可以看做detached實例。

persist()方法的參數為transient實例,即不帶主鍵id的實例。save()方法參數也為transient實例,但是也可以給此實例設置id屬性,即detached實例,

只不過此id屬性不起作用(native生成方式下)。結論如下:

save()和persist()方法參數雖然都說明為transient實例,但是也可以傳detached實例,也可以傳persistent實例。但是沒有理由傳非transient實例,因為這些方法都是設計為傳transient實例的,雖然傳其他實例也可以,但是不推薦,誰知道100年后hibernate90.10.9會不會改變save()或persist()方法傳入非transient實例的行為呢。

3 合並對象到數據庫 session.merge(Object user); //參數user為detached實例,其屬性將被copy到persistent實例。並且返回此persistent實例

拷貝user到持久化對象。如果沒有persistent對象在session緩存中,則加載數據到persistent對象並且返回此persistent對象。

如果user在數據庫中沒有對應記錄,則拷貝user到一個副本作為persistent對象並且返回這個persistent對象。user不會被保存到session緩存中



1) 保存未設置id屬性的User對象,執行insert把User對象保存到數據庫中,同時返回保存后的User對象。

    @Test
    public void testMerge() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan2");
            User user1 = (User) session.merge(user); //把user屬性拷貝到新建的user1對象,執行insert插入數據庫,並且返回新建的user1對象,user1包含id,在session緩存中
            System.out.println(user1 == user); //返回false。user為新建的對象,並沒有放入session緩存。user1為新建的持久化對象,並且在session的緩存中。
        } catch (HibernateException e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

2) 保存設置id屬性的User對象,首先執行select查詢數據庫。若數據庫中存在此id的記錄,並且與數據庫中記錄不一致,則執行update操作,

若不存在此記錄,否則執行insert操作。

    @Test
    public void testMerge1() {
        try {
            User user = new User();
            user.setBirthday(new java.sql.Date(0));
            user.setName("binyulan123");
            user.setId(20);
            /**
             * 把user屬性拷貝到新建的User對象,並且執行select查詢數據庫。
             * 假設數據庫中存在id為20的記錄,且user對象與數據庫中記錄不一致,執行update
             */
            User user1 = (User) session.merge(user); 
            System.out.println(user1 == user); //返回false。user為參數,不在session緩存中,user1為新建的持久化對象,並且在session的緩存中。
            
            /**
             * 把user屬性拷貝到新建的User對象,並且執行select查詢數據庫。
             * 假設數據庫中不存在id為123456789的記錄,執行insert
             */
            user.setId(123456789L);
            User user2 = (User) session.merge(user); 
            System.out.println(user2 == user); //返回false。user為參數,不再session緩存中,user2為新建的持久化對象,並且在session的緩存中。
        } catch (HibernateException e) {
            e.printStackTrace();
            if (transaction != null) {
                transaction.rollback();
            }
            throw e;
        }
    }

4 數據更新,session.update(Object user);// 參數為一個detached實例。

使用user更新數據庫中記錄,並且把user對象變為persistent實例。

    @Test
    public void testUpdate() {
        User user = new User();
        user.setName(null);
        user.setBirthday(null);
        user.setId(20);
        session.update(user);
    }

 

5 更新或者保存,session.saveOrUpdate(Object  user);

    @Test
    public void testSaveOrUpdate() {
        User user = new User();
        user.setName(null);
        user.setBirthday(null);
        session.saveOrUpdate(user); //insert操作
        
        User user1 = new User();
        user1.setName(null);
        user1.setBirthday(null);
        user1.setId(9);
        session.saveOrUpdate(user1);//update操作
    }

6 刪除操作,session.delete(Object user);

從session緩存中刪除一個persistent實例。參數為一個Session緩存中的實例或者一個帶id的transient實例

    @Test
    public void testDelete() {
        User user = new User();
        user.setId(9);
        session.delete(user);
    }

7 查詢操作,session.get(Class clazz, Serializable id);

根據給定的Class對象和主鍵id返回persistent實例,如果數據庫中沒有此記錄,則返回null。

    @Test
    public void testGet() {
        User user = (User) session.get(User.class, 1L);
        System.out.println(user);
    }

8 查詢操作,session.load(Class theClass, Serializable id);

返回一個代理對象,並在訪問非主鍵id屬性時會初始化這個代理對象。不能使用這個方法判斷是否一個實例存在。即使數據庫中沒有相應記錄,也會返回代理對象,但是在使用此代理對象是就會報錯。

@Test
    public void testLoad() {
        User user = (User) session.load(User.class, 1L); //返回的user為代理對象
        user.getName(); //訪問name屬性時向數據庫發送SQL select
        System.out.println(user.getClass()); //代理對象類
    }

9 復制操作,replicate(Object object, ReplicationMode replicationMode);

    @Test
    public void testReplicate() {
        User user = new User();
        user.setId(48);// 假定數據庫中存在id為48的記錄
        user.setBirthday(new java.sql.Date(0));
        user.setName("binyulan1");
        /**
         * 可以選擇復制的模式,OVERWRITE模式為如果存在此記錄,則覆蓋
         * 執行SQL select
         */
        session.replicate(user, ReplicationMode.OVERWRITE);
        session.flush();// 執行SQL update
        
        User user1 = new User();
        user1.setId(48);
        user1.setBirthday(new java.sql.Date(0));
        user1.setName("binyulan2");
        /**
         * 可以選擇復制的模式,IGNORE模式為如果存在此記錄,則不進行更新
         * 執行SQL select
         */
        session.replicate(user1, ReplicationMode.IGNORE);
        session.flush();// 記錄存在,所以忽略掉,不會執行SQL update
        
        User user3 = new User();
        user3.setId(48);
        user3.setBirthday(new java.sql.Date(0));
        user3.setName("binyulan3");
        /**
         * 可以選擇復制的模式,EXCEPTION模式為如果存在此記錄,則拋異常
         * 此語句執行SQL insert,ReplicationMode.EXCEPTION 始終都會執行SQL insert。
         * 使用數據庫自身約束拋出異常,因為使用的是native主鍵生成方式,所以此處不拋異常,會插入成功
         */
        session.replicate(user3, ReplicationMode.EXCEPTION);
    }

 10 強制同步數據到數據庫,session.flush();

可以設置FlushMode, 如果設置為NERVER,且不手動執行session.flush(), 提交事務也不會執行SQL update。

System.out.println(session.getFlushMode()); //默認模式為AUTO

    @Test
    public void testFlush() {
        User user = new User();
        user.setId(1); //假設id為1的記錄存在
        user.setBirthday(new java.sql.Date(0));
        user.setName("binyulan3");
        session.update(user);
        session.flush(); //強制執行SQL update
    }

11 同步數據庫中數據到java對象,session.refresh(Object user); //參數為persistent實例或者detached實例

 重新讀取數據庫記錄到user,不建議在跨多個業務長時間運行的session中使用。在以下特定場景中使用

  1) 觸發器出發了一個insert或者update
  2) 執行一大堆sql后
  3) 插入一個Blob或Clob后

@Test
    public void testRefresh() {
        User user = (User) session.get(User.class, 1L);
        user.setName("original");
        session.refresh(user); //重新同步數據庫中記錄到user,此時user的name不是original
        System.out.println(user.getName()); // 輸出binyulan
    }

 

 

請勿轉載,謝謝合作

原創地址:http://www.cnblogs.com/binyulan/p/5628579.html  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM