標籤:new 有用 技術分享 update teacher ima 是否一致 value test
第二節:Session 常用方法講解 2)load和get()方法:資料庫中不存在與OID 對應的記錄,Load()方法會拋出異常:load方法預設採用消極式載入,load出來的對象是一個代理類。開始並沒有值,只有用到它的屬性等的時候,才會去發出sql語句。而get方法一開始就發出sql語句。 如果說擷取一個對象是為了刪除它,可以用load,因為只要擷取個引用就行了。如果說擷取一個對象是為了訪問它的屬性,建議用get;
@Test public void testLoadClass() { Class c = (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); }
View Code
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 session2=sessionFactory.openSession(); session2.beginTransaction(); c.setName("08電腦本科2"); session2.update(c); session2.getTransaction().commit(); session2.close(); }
View Code
補充:
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