《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