《Hibernate學習筆記五》Session 的update方法詳解

《Hibernate學習筆記五》Session 的update方法詳解

在前面的學習中,我們用到了Session的save方法,將對象從tansient狀態轉化爲persistent狀態。下面我們就來學習Session的update方法。

在hibernate api文檔中,Session接口提供了兩種重載了update方法,分別如下:

1、void update(Object object) :Update the persistent instance with the identifier of the given detached instance.

此方法文檔中的意思就是:根據唯一的標識將一個detached狀態的對象更新爲persistent狀態。

第一個例子:detached狀態的對象可以update

這個例子就是先new了一個對象,用session的save方法進行持久化,持久化後,對象進入到detached狀態,之後我們進行更新操作,這樣是可以更新的。

package com.hibernate.mode;

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.Test;

    import com.hibernate.model.Teacher;

    public class TeacherTest {
    private static SessionFactory sessionFactory;
    @BeforeClass
    public static void beforeClass(){
        sessionFactory = new Configuration().configure().buildSessionFactory();
    }
    @Test
    public void testUpdate1() {
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        //新new的對象處於transient狀態
        Teacher t=new Teacher();
        t.setName("wuranghao");
        t.setTitle("professior");
        session.save(t);
        session.getTransaction().commit();
        //commit之後,對象t就進入detached狀態,下面我們用update方法對其進行更新
        Session session2=sessionFactory.getCurrentSession();
        session2.beginTransaction();
        t.setName("haohao");
        session2.update(t);
        session2.getTransaction().commit();
    }
    @AfterClass
    public static void afterClass(){
        sessionFactory.close();
    }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

運行後在數據庫中查詢的結果如下,從結果可以看出,對象是更新成功了的。

第二個例子:transient狀態沒有設唯一標識符的對象是不能夠update的

@Test
    public void testUpdate2() {
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        Teacher t=new Teacher();
        t.setName("wuranghao");
        t.setTitle("professior");
        //新new的對象t此時是transient狀態,看是否能夠對其update
        session.update(t);
        session.getTransaction().commit();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

transient 狀態沒有設唯一標識符ID的對象是不能夠update的。

第三個例子:transient狀態設有唯一標識符的對象且對應數據庫表中沒有設置這個Id的記錄也是不能夠update的

@Test
    public void testUpdate3() {     
        Teacher t=new Teacher();
        t.setId(2);
        t.setName("wuranghao");
        t.setTitle("professior");
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        //新new的對象t此時是transient狀態,看是否能夠對其update
        session.update(t);
        session.getTransaction().commit();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

第四個例子:transient狀態設有唯一標識符的對象且數據庫中有對象設置的對應Id的記錄是能夠update的

上面這句話可能不太好理解,意思就是說,如果數據庫中有一條id=0的記錄,然後我們就可以將transient狀態的對象+此對象setId(0),則此對象是可以被update的。

在測試下面這個方法前,數據庫的內容如下: 

@Test
    public void testUpdate3() {     
        Teacher t=new Teacher();
        t.setId(0);
        t.setName("wuranghao");
        t.setTitle("professior");
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        //新new的對象t此時是transient狀態,看是否能夠對其update
        session.update(t);
        session.getTransaction().commit();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

測試代碼運行後,數據庫的結果如下: 

第五個例子:對persistent狀態的對象的屬性內容進行更改會自動的update到數據庫

下面的例子是利用了Session的get方法從數據庫中導出一個相應Id的記錄並轉化爲Teacher對象實例,此時的對象是處於persistent狀態。

@Test
    public void testUpdate4() {     
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        Teacher t=session.get(Teacher.class, 0);//從數據庫中提取id=0的記錄並轉化爲Teacher對象實例。
        //get出來的對象是persistent狀態,對persistent狀態的對象進行更改,則一定回自動的update
        t.setName("wuwu");
        session.getTransaction().commit();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

這樣就會自動觸發update語句,但是,如果更改前後的內容完成一樣,則不會觸發update語句。只有對象在緩存中的內容和數據庫的記錄不一樣時,纔會觸發update語句進行更新。

關於Session的update方法總結

1、用來更新detached對象,更新完成後轉爲persistent狀態。

2、更新transient對象會報錯

3、更新自己設定的唯一標識符(例如:Id)的transient對象且數據庫有對應記錄的可以update。

4、處於persistent狀態的對象,對這個對象的屬性內容進行更改後當commit時會自動觸發Session update方法。有一點需要注意的是如果更改前後的內容完成一樣,則不會觸發update語句。只有對象在緩存中的內容和數據庫的記錄不一樣時,纔會觸發update語句進行更新。

上面的update有一個問題,問題是:無論我們更改了對象的幾個屬性,當持久化的時候,都會更新所有的記錄,這顯然是不好的。

下面就來介紹下,如果只更新修改了的字段。

更新部分更改的字段

更新部分更改的字段,有以下三種方法。

1、xml設定property標籤的update屬性,annotation設定@Column的updatable屬性

這種方式不靈活,因此很少用。下面不再進行詳細介紹。

2、使用xml中的dynamic-update

注意,在XXX.hbm.xml文件中的設置dynamic-update=”true” 這樣就可以實現部分只進行了更改字段的更新。

<class name="Teacher" table="teacher" dynamic-update="true">
    </class>
  • 1
  • 2

完整配置文件內容如下:

<?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.hibernate.model">
    <class name="Teacher" table="teacher" dynamic-update="true">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name"/>
        <property name="title"/>
    </class>
    </hibernate-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

但是這種方法不能跨Session。在一個Session中,當我們在XXX.hbm.xml文件中加上了dynamic-update=”true”,則就只會更新我們修改的字段。看下面的例子:

    @Test
    public void testUpdate4() {     
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        Teacher t=session.get(Teacher.class, 0);//從數據庫中提取id=0的記錄並轉化爲Teacher對象實例。
        //get出來的對象是persistent狀態,對persistent狀態的對象進行更改,則一定回自動的update
        t.setName("wuwuwuwu");
        session.getTransaction().commit();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

當我們運行這個Test的時候,Hibernate發出瞭如下的MySQL語句,從該語句可以看出,只更新了name字段,這就是我們想要的結果;

但是,當我們跨Session後,即使我們在XXX.hbm.xml文件中加上了dynamic-update=”true”,則就在第二次更新的時候就並不是只更新我們修改的字段了。

看如下的例子:

    @Test
    public void testUpdate5() {     
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        Teacher t=session.get(Teacher.class, 0);//從數據庫中提取id=0的記錄並轉化爲Teacher對象實例。
        //get出來的對象是persistent狀態,對persistent狀態的對象進行更改,則一定回自動的update
        t.setName("xiao");
        session.getTransaction().commit();
        //另外一個Session
        Session session2=sessionFactory.getCurrentSession();
        session2.beginTransaction();
        t.setName("xiaoxiao");
        session2.update(t);
        session2.getTransaction().commit();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

運行結果如下: 
 
在上面這個例子中Teacher.hbm.xml文件中加上了dynamic-update=”true” ,而測試函數有兩個Session,在第二個Session中,我們修改了處於detached狀態下的對象的name屬性,當調用update方法時,並不是只更新name字段,而是更新了這條記錄的所有字段 。

如果我們既想採用這種方法(即在XXX.hbm.xml文件中添加dynamic-update=”true”)來實現只更新我們修改的字段,又想跨Session,則解決方法就是:在第二個以之後的Session 中我們不使用session2.update(t)來更新,而是採用session2.merge(t)來進行合併更新。

所以這種方法我們也不推薦。

3、使用HQL(EJBQL) ,建議使用這種方法。

例子程序如下:

利用 Query來進行字段的更新 。

    @Test
    public void testUpdate6() {     
        Session session=sessionFactory.getCurrentSession();
        session.beginTransaction();
        //org.hibernate.Query     
    //語句的Teacher指的是類,不是數據庫的表名
        Query q=session.createQuery("update Teacher t set t.name='wuranghao' where t.id=0");
        q.executeUpdate();
        session.getTransaction().commit();

} from: http://blog.csdn.net/u010412719/article/details/51283926

發佈了8 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章