在介紹hibernate的更新之前,我們先來看看session的兩個方法。load和get方法;這兩個方法是獲取數據的根據對象的id值;
先看兩段代碼。load和get的方法都含有兩個參數,前者是得到的對象類型。后者是一個可序列化的值,說白了也就是你要獲取數據庫里面對應的主鍵的值,你的主鍵如果是id。你獲取的是第一條記錄那么則是一,如果你的主鍵是name。你就寫上某個名字。然后獲取這個名字對應的數據記錄。
當我們執行下面兩條語句的時候,我們會發現第一條報錯。而第二條是沒有什么問題的。
但是如果我們把兩個里面的打印語句都寫到commit之前的時候。我們發現兩個都不會報錯了。
@Test public void testload(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.load(Teacher.class, 1); session.getTransaction().commit(); System.out.println(t.getName()); } @Test public void testget(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); session.getTransaction().commit(); System.out.println(t.getName()); }
這里面是有原因的。當用load獲取的時候,其實執行load語句只是將對象置入到內存中。而執行get方法的時候。不但將對象放入到了內存而且。對象執行了sql語句。對象的值已經在getName方法執行已經賦值了。而load方法。在執行getName方法的時候才執行sql語句,從數據庫里面獲取相關的記錄。當我們在執行getName方法前后加上時間的時候。我們得到時間差的話我們會發現,我load這種情況下getName費許多的時間。而get這種情況幾乎沒有費什么時間。
那么為什么在提交之后,load得到getName的方法會出錯呢。那是因為提交完之后。當前的session自動關閉了。當然這是getCurrentSession的情況下。而再去調用鍍錫的getName方法的時候。session對象關閉了。相等於緩存中沒有對應的記錄了。只有數據庫和內存中有。此時再無獲取getname的時候沒有中間橋梁session。那么肯定出錯。而get方法的話。因為已經在get方法執行的時候將數據賦值給了對象。那么我們獲取的時候直接從內存里面拿去好了。用不着經由session去訪問數據庫。所以不會出錯。
下面來具體談談更新數據的情況
更新數據我們的第一反應是從數據庫里面講數據拿出來然后改變某些值,然后再調用update的方法完成操作。這種方法是對的。但是不是只有這一種方法的。我們還有不通過調用update方法就可以完成更新。update方法里面傳入的對象。一定要有主鍵的值。並且主鍵的記錄一定可以在數據庫里面找得到,這樣才不會報錯的。所以我們可以先不用從數據庫里面拿去對象。而是先定義一個對象。之后再給此對象賦值。然后更新此對象。如果給的值在數據庫中含有那么對應的記錄也可以然后更新。
1.常規方法先從數據庫里面拿取,然后更新
Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); t.setName("wsx"); session.update(t) session.getTransaction().commit();
2.先創建一個對象,然后給其賦值。再更新。
Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=new Teacher(); t.setName("wsx"); session.update(t) session.getTransaction().commit();
以上這兩種方法都可以完成更新的操作。
而以下的這種方法也是可以完成更新的。並且沒有用到update方法;
Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); t.setName("wsx"); session.getTransaction().commit();
我們仔細瞧下來會發現。它與第一個方法的不同之處就是沒有用到update方法。難道這也行嗎?嗯。我肯定的告訴你。
接下來我們探究其道理。
當我們執行get方法的時候,其實在內存中,緩存session中,數據庫中都有對應的Teacher對象。而當我們改變其內存中對象的名字的時候。我們再提交的話,其實是數據庫事務會去檢測,內存中的session對象的值和緩存session中的值是否一致,不一致的話,那么則提交更新。
更新數據時遇到的問題。
我們會發現更新數據的時候。如果一個表中有五個字段,而我們只更新一個字段比較說更新年齡字段的時候。那么我們會從打印日志中驚奇的發現我們的其他幾個字段也更新了。這種更新方式是很不友好的。代價也很巨大。也許本來你只需更新一個年齡的值。而其他字段里面有一篇文章。那么你只簡簡單單更新一個年齡卻引起一篇文章的更新。
根據這一問題,我們有一些幾個解決問題的辦法
1.通過annotation在某個不需要更新的字段的get方法之前加上@column(updatable=false);
@Column(updatable=false) ublic String getName() { return name;
這種方法的缺點是這個字段永遠不會更新。這個我們一想就感覺很不靈活。也許某一天這個字段需要更新。但是也有永不更新的情況。這個很多。比如一個銀行的名字。等待。
2.在xml配置文件里面class加上dynamic——update=true;
Xml代碼
<hibernate-mapping> <class name="com.bjsxt.hibernate.Student" dynamic-update="true"> <id name="id" column="id"/> <property name="name" /> <property name="age" /> </class> </hibernate-mapping>
這樣就會自動更新。但是我們的自動更新某些需要更新的列的話,我們必須要在同一個session中。不同的session。找不到參考依據的話,那么也會集體更新的。
@Test public void testupdate1(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Teacher t=(Teacher) session.get(Teacher.class, 1); t.setName("wsx"); session.update(t); session.getTransaction().commit(); t.setName("wsx1"); Session session1 =null; session1 =sessionFactory.getCurrentSession(); session1.beginTransaction(); session.update(t); session.getTransaction().commit(); }
第一個session的update方法只會更新name。而第二個全部屬性都會更新;
3.用hql語句。你需要更新那個列,那么則寫成相應的形式;
Java代碼 @Test public void testupdate2(){ Session session =null; session =sessionFactory.getCurrentSession(); session.beginTransaction(); Query q=session.createQuery("update tablename set name='wsx' where id=1 "); q.executeUpdate(); session.getTransaction().commit(); }
我們很多情況下用到第三種方式。 好了更新就講到這兒。