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();
持久化transient實例。參數為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();
持久化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實例。
3 合並對象到數據庫 session.merge();
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; } }
寫累了,明天再寫,未完待續
請勿轉載,謝謝合作