Hibernate學習5—Hibernate操作對象2
阿新 • • 發佈:2017-07-29
之前 on() nbsp select語句 代理 teacher 內存 不存在 png 第二節:Session 常用方法講解
2)load和get()方法:
數據庫中不存在與OID 對應的記錄,Load()方法會拋出異常:
load方法默認采用延遲加載,load出來的對象是一個代理類。開始並沒有值,只有用到它的屬性等的時候,才會去發出sql語句。
而get方法一開始就發出sql語句。
如果說獲取一個對象是為了刪除它,可以用load,因為只要獲取個引用就行了。
如果說獲取一個對象是為了訪問它的屬性,建議用get;
@Test public void testLoadClass() { Class cView Code= (Class) session.load(Class.class, Long.valueOf(2)); //class id為2的不存在,拋出異常 System.out.println(c.getStudents()); } @Test public void testGetClass() { Class c = (Class) session.get(Class.class, Long.valueOf(2)); //class id為2的不存在,打印null System.out.println(c); }
2)update:
@Test public void testUpdateClass(){ Session session1=sessionFactory.openSession(); session1.beginTransaction(); Class c=(Class)session1.get(Class.class, Long.valueOf(1)); session1.getTransaction().commit(); session1.close(); Session session2View Code=sessionFactory.openSession(); session2.beginTransaction(); c.setName("08計算機本科2"); session2.update(c); session2.getTransaction().commit(); session2.close(); }
補充:
update方法: 1.更新一個detached的對象; 2.更新一個transient的會報錯;但是更新自己設定id的transient對象可以(數據庫有對應記錄); 3.上面的,比如更新teacher,我們只是想更新name,但是它會把所有的屬性都更新一遍;這樣會造成效率低,比如有個字段特別長... 4.持久化的對象,只要改變了它的內容,session在提交或者關閉的時候,會檢查緩存中的和數據庫中的是否一致,如果不一致,自動的發update語句; 但是也和上面一樣,雖然只改了一個字段,也會更新所有的字段; 5.能不能做到:哪個字段改了才更新,哪個字段沒改,哪個字段就不更新?怎麽做: a.xml配置: <class name="com.cy.Teacher" dynamic-update="true">.....</class> b.跨session更新的問題: @Test public void testUpdate5() { Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Student s = (Student)session.get(Student.class, 1); s.setName("zhangsan5"); session.getTransaction().commit(); s.setName("z4"); Session session2 = sessionFactory.getCurrentSession(); session2.beginTransaction(); session2.update(s); session2.getTransaction().commit(); } 首先student對象被我們放到了緩存裏,s.setName("zhangsan3"),Hibernate會檢查哪些屬性改過了,這時候生成sql語句,由於使用了dynamic-update,它就只更新name這個字段了; session提交之後,關閉了。緩存中的這個對象沒了。但是內存中Student s這個對象還在,是detached狀態的。 這個對象又setName("z4"),第二個session2來了,這個session2裏面沒有s這個對象,然後update(s),它有沒有地方來比較哪個字段改過了? 沒有,它沒法將內存中的s和session2緩存中的s來比較,所以update(s),發出的sql會更新全部的字段; c.根據上面,如果想跨session,只更新改過的字段,怎麽做: 將上面的update改為merge: @Test public void testUpdate6() { Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Student s = (Student)session.get(Student.class, 1); s.setName("zhangsan6"); session.getTransaction().commit(); s.setName("z4"); Session session2 = sessionFactory.getCurrentSession(); session2.beginTransaction(); session2.merge(s); session2.getTransaction().commit(); } merge:把這個對象給我合並到數據庫;原來沒改的內容還需要合並嗎?不需要。 merge的時候,它怎麽檢查哪些字段改過哪些字段沒改過呢?緩存中又沒有,只能從數據庫中load一次,所以它在update之前先發出了一條select語句,然後再比較你給我的對象和我load的對象在什麽地方不同,再重新發update語句。 d:dynamic-update這種xml配置,對應的JPA Annotation沒有對應的屬性; 在真正開發中建議使用HQL: session.createQuery("update Student s set s.name=‘z5‘ where s.id = 1"); @Test public void testUpdate7() { Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); Query q = session.createQuery("update Student s set s.name=‘z5‘ where s.id = 1"); q.executeUpdate(); session.getTransaction().commit(); }
3)saveOrUpdate:
saveOrUpdate(): 如果傳的是一個臨時對象,則執行save方法;如果傳的是遊離對象,就調用update方法;@Test public void testSaveOrUpdateClass(){ Session session1=sessionFactory.openSession(); session1.beginTransaction(); Class c=(Class)session1.get(Class.class, Long.valueOf(1)); session1.getTransaction().commit(); session1.close(); Session session2=sessionFactory.openSession(); session2.beginTransaction(); c.setName("08計算機本科3"); Class c2=new Class(); c2.setName("09計算機本科3"); session2.saveOrUpdate(c); //c是遊離狀態,執行update session2.saveOrUpdate(c2); //c2臨時狀態,執行save session2.getTransaction().commit(); session2.close(); /** * 發出的sql: * Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=? Hibernate: insert into t_class (className) values (?) Hibernate: update t_class set className=? where classId=? */ }View Code
4)merge:
有的時候update會報錯:session中有兩個對象,擁有相同的OID(比如OID為1),更新的時候,session發現緩存中你已經有一個OID為1的對象了,所以更新的時候就報錯了; 比如:@Test public void testUpdateClass2(){ Session session1=sessionFactory.openSession(); session1.beginTransaction(); Class c=(Class)session1.get(Class.class, Long.valueOf(1)); session1.getTransaction().commit(); session1.close(); Session session2=sessionFactory.openSession(); session2.beginTransaction(); Class c2=(Class)session2.get(Class.class, Long.valueOf(1)); c.setName("08計算機本科3"); session2.update(c); session2.getTransaction().commit(); session2.close(); }View Code
執行報錯:
為了解決這個問題,多了個merge方法,合並對象: 更新的時候如果發現這個對象OID和session緩存中另一個對象OID重合了,調用merge方法就會合並,把這兩個對象的屬性合並,然後更新;
@Test public void testMergeClass(){ Session session1=sessionFactory.openSession(); session1.beginTransaction(); Class c=(Class)session1.get(Class.class, Long.valueOf(1)); session1.getTransaction().commit(); session1.close(); Session session2=sessionFactory.openSession(); session2.beginTransaction(); Class c2=(Class)session2.get(Class.class, Long.valueOf(1)); c.setName("08計算機本科4"); session2.merge(c); session2.getTransaction().commit(); session2.close(); }View Code
5)delete:
@Test public void testDeleteStudent(){ Student student=(Student)session.load(Student.class, Long.valueOf(1)); session.delete(student); session.getTransaction().commit(); session.close(); }View Code
因為刪除的時候,只需要獲得它的引用,這裏使用了load延遲加載就行了。不需要使用get了,因為不需要獲取它裏面的屬性。
session.delete的時候還沒有真正刪除,提交事務的時候,才同步數據庫,真的刪了。
Hibernate學習5—Hibernate操作對象2