(2)session.merge ()方法
該方法將修改表中記錄,其所需要的實體狀態爲脫管狀態,但是注意,它並不影響調用方法前後的狀態,也即該實體依然是脫管狀,見例6.4。
例6.4:session.merge ()方法對狀態的變化
public void run() {
//創建UserInfo實例
UserInfo userInfo = new UserInfo();
//使之成爲脫管狀態
userInfo.setId(11112);
userInfo.setName("RW3");
userInfo.setSex("M");
//創建UserInfo實例
UserInfo userInfo2 = new UserInfo();
//使之成爲脫管狀態
userInfo2.setId(11112);
userInfo2.setName("RW4");
userInfo2.setSex("F");
//啓動Session
Session session = HibernateSessionFactory.currentSession();
//啓動事務
Transaction tx = session.beginTransaction();
//調用merge方法,此時UserInfo實體狀態並沒有被持久化
session.merge(userInfo);
//調用merge方法,此時UserInfo實體狀態並沒有被持久化
//但是數據庫中的記錄被更新了
①session.merge(userInfo2);
//merge方法與update方法的差別在於針對同樣的操作update方法會報錯
//原因在於update方法使得實體狀態成爲了持久化狀態,而Session中不允許兩個持久化實體有同樣的持久化標識
②//session.update(userInfo);
//session.update(userInfo2);
//以下兩句不會發送SQL,因爲userInfo2不是持久化狀態的實體
③userInfo2.setName("RW5");
userInfo2.setSex("M");
//提交事務
tx.commit();
//關閉Hibernate Session
HibernateSessionFactory.closeSession();
}
針對該段代碼將執行如下SQL語句:
Hibernate:
/* ①session.merge(userInfo2)的動作 */
select
userinfo0_.id as id0_0_,
userinfo0_.NAME as NAME0_0_,
userinfo0_.SEX as SEX0_0_,
userinfo0_.roomid as roomid0_0_
from
userinfo userinfo0_
where
userinfo0_.id=?
Hibernate:
/* ①session.merge(userInfo2)的動作 */
update
userinfo
set
NAME=?,
SEX=?,
roomid=?
where
id=?
session.merge()方法會首先發送一句select語句,去數據庫端獲取UserInfo持久化標識所對應的表記錄;然後自動生成一個持久化狀態的UserInfo實體,與脫管狀態的UserInfo實體做比較是否有所改變;一旦發生了改變,纔會發送update語句執行更新。而按執行順序,若兩句session.merge()方法針對同一個脫管狀態的UserInfo實體,那其結果只會執行最後一個session.merge()方法所發出的update語句。即使執行了session.merge()方法,UserInfo實體依然是脫管狀態,因此③userInfo2. setName("RW5")的語句不會同步數據庫中的表。
(3)session.lock()方法
他爲了解決事務處理而使用,它會將實體從脫管狀態轉變爲持久化狀態。但是值得注意的是,調用session.lock()方法後,脫管狀態的實體信息不會同步到數據庫,而是會從數據庫中返回該持久化狀態。即使在脫管狀態對實體屬性進行了修改,一旦調用了session.lock()方法,這種修改就成了無效,見例6.5。
例6.5:session.lock()方法對狀態的變化
public void run() {
//創建UserInfo實例
UserInfo userInfo = new UserInfo();
//使之成爲脫管狀態
userInfo.setId(11112);
userInfo.setName("RW3");
userInfo.setSex("M");
//啓動Session
Session session = HibernateSessionFactory.currentSession();
//啓動事務
Transaction tx = session.beginTransaction();
//發送select獲取數據庫中的當前記錄(執行的SQL根據LockMode不同有不同的方式)
//UserInfo實體將從脫管狀態轉變爲持久化狀態
①session.lock(userInfo,LockMode.UPGRADE_NOWAIT);
//對當前UserInfo實體進行更新將同步數據庫中的記錄
②userInfo.setName("RW8");
//提交事務
tx.commit();
//關閉Hibernate Session
HibernateSessionFactory.closeSession();
}
針對該段代碼將執行如下SQL語句:
Hibernate:
/* ①session.lock(userInfo,LockMode.UPGRADE_NOWAIT)的動作 */
select
id
from
userinfo
where
id =? for update
nowait
Hibernate:
/*②userInfo.setName("RW8")的動作 */
update
userinfo
set
NAME=?,
SEX=?,
roomid=?
where
id=?
session.lock()方法並不是爲了將脫管狀態的對象轉變爲持久化狀態,而是爲了事務處理。
(4)session.saveOrUpdate()方法
它是Hibernate提供的既可以新增也可以更新的方法,該方法使實體狀態從脫管或瞬時直接變成持久化。session.saveOrUpdate()方法對實體的持久化標識非常敏感。當實體持久化標識存在,就會發送update SQL,當持久化標識不存在,就會發送insert SQL,見例6.6。
例6.6:session.saveOrUpdate()方法對狀態的變化
public void run() {
//創建UserInfo實例
UserInfo userInfo = new UserInfo();
//使之成爲脫管狀態
userInfo.setId(11112);
userInfo.setName("RW3");
userInfo.setSex("M");
//創建UserInfo實例,其爲瞬時狀態
UserInfo userInfo2 = new UserInfo();
userInfo2.setName("RW3");
userInfo2.setSex("M");
//啓動Session
Session session = HibernateSessionFactory.currentSession();
//啓動事務
Transaction tx = session.beginTransaction();
//UserInfo存在持久化標識,因此爲新增,從瞬時狀態成爲持久化狀態
①session.saveOrUpdate(userInfo2);
//同步數據庫表記錄
②userInfo2.setName("RW9");
//UserInfo存在持久化標識,因此爲修改,從脫管狀態成爲持久化狀態
③session.saveOrUpdate(userInfo);
//同步數據庫表記錄
④userInfo.setName("RW10");
//提交事務
tx.commit();
//關閉Hibernate Session
HibernateSessionFactory.closeSession();
}
針對該段代碼將執行如下SQL語句:
Hibernate:
/* ①session.saveOrUpdate(userInfo2)的動作 */
insert
into
userinfo
(NAME, SEX, roomid, id)
values
(?, ?, ?, ?)
Hibernate:
/* ②session.saveOrUpdate(userInfo)的動作 */
update
userinfo
set
NAME=?,
SEX=?,
roomid=?
where
id=?
Hibernate:
/* ③session.saveOrUpdate(userInfo)的動作 */
update
userinfo
set
NAME=?,
SEX=?,
roomid=?
where
id=?
根據代碼的執行,對同一持久化UserInfo屬性需要改變多次,那隻會以最後的屬性爲準,因此③session.saveOrUpdate(userInfo)和④userInfo.setName("RW10")雖然從理論上需要發送兩句update SQL到數據庫,但其實只會產生一句。
(5)session.createQuery()方法
它爲HQL語句調用,HQL(HibernateQusery Language)是Hibernate框架自定義的一種面向對象的語言,類似SQL語言,用以與數據庫進行交互。Hibernate將HQL解析成SQL語句與數據庫交互。HQL被執行後,其所關係到的實體對象將從瞬時狀態轉變爲脫管狀態,見例6.7。
例6.7:session.createQuery()方法對狀態的變化
//一個內部類,作爲SQL查詢的參數傳遞
class RoomDTO {
Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
public void run() {
// 創建一個JavaBean作爲參數傳遞
RoomDTO roomDTO = new RoomDTO();
//設置id屬性的值
roomDTO.setId(1L);
// 啓動Session
Session session = HibernateSessionFactory.currentSession();
// 啓動事務
Transaction tx = session.beginTransaction();
//session.createQuery方法作爲HQL查詢的執行
//其中setProperties方法作爲":id"的參數傳遞,要求roomDTO實例中必須包含id
//屬性和getId、setId方法
//由於SQL中包含有3個實體:room、room.id、userinfo,因此返回的結果將是對象數組
①Iterator i = session
.createQuery(
"select room, room.id, userinfo from Room room, UserInfo userinfo where room.id = userinfo.room.id and room.id = :id")
.setProperties(roomDTO).iterate();
//通過迭代將3個實體對象轉型,得到最終結果
//其中Room實體和UserInfo實體對應的實體狀態爲脫管,roomid則爲一個Long類型
while (i.hasNext()) {
//獲取對象數組轉型
Object[] object = (Object[]) i.next();
//獲取脫管狀態的Room實體
②Room roomr = (Room) object[0];
System.out.println(roomr.getName());
System.out.println(roomr.getRoomnumber());
//獲取roomid
③Long roomid = (Long) object[1];
System.out.println(roomid);
//獲取脫管狀態的UserInfo實體
④UserInfo userinfor = (UserInfo) object[2];
System.out.println(userinfor.getName());
System.out.println(userinfor.getSex());
}
// 提交事務
tx.commit();
// 關閉Hibernate Session
HibernateSessionFactory.closeSession();
}
針對該段代碼將執行如下SQL語句:
Hibernate:
/* 執行
①select
room,
room.id,
userinfo
from
Room room,
UserInfo userinfo
where
room.id = userinfo.room.id
and room.id = :id
的HQL語句 */
select
room0_.id as col_0_0_,
room0_.id as col_1_0_,
userinfo1_.id as col_2_0_
from
room room0_,
userinfo userinfo1_
where
room0_.id=userinfo1_.roomid
and room0_.id=?
Hibernate:
/* ②Room roomr = (Room) object[0]的動作(數據庫中有一條記錄,取第一條) */
select
room0_.id as id1_0_,
room0_.NAME as NAME1_0_,
room0_.roomnumber as roomnumber1_0_
from
room room0_
where
room0_.id=?
Hibernate:
/* ④UserInfo userinfor = (UserInfo) object[2]的動作(數據庫中有兩條記錄,取第一條) */
select
userinfo0_.id as id0_0_,
userinfo0_.NAME as NAME0_0_,
userinfo0_.SEX as SEX0_0_,
userinfo0_.roomid as roomid0_0_
from
userinfo userinfo0_
where
userinfo0_.id=?
Hibernate:
/* ④UserInfo userinfor=(UserInfo)object[2]的動作(數據庫中有兩條記錄,取第二條)*/
select
userinfo0_.id as id0_0_,
userinfo0_.NAME as NAME0_0_,
userinfo0_.SEX as SEX0_0_,
userinfo0_.roomid as roomid0_0_
from
userinfo userinfo0_
where
userinfo0_.id=?
可以看到,Hibernate在執行這段代碼的HQL時,並不會一次性把所有的room表和userinfo表的字段都撈取出來,而是先獲取其主鍵。在之後真正要使用這兩個表所對應的實體對象(Room和UserInfo)時,纔會調用select語句去獲取其所有字段,這是“延時求值”的機制在起作用。session.createQuery()方法不會使實體成爲持久化狀態,因此對Room和UserInfo的實體屬性進行改變不會同步數據庫。
調用createQuery()方法執行HQL時,有多種方式可以傳遞參數,本例提供了一種常見的方式——setProperties()。
說明 除了createQuery()方法外,Hibernate還提供了外置命名查詢(getNameQuery()方法)、結果集過濾(createFilter()方法)、條件查詢(createCriteria()方法)、原生SQL查詢(createSQLQuery()方法)來實現抓取數據。
6.1.6 結語
在本小節中,將對Hibernate中的持久化方法做一個總結,也作爲本問題的結語。
(1)瞬時—脫管狀態的方法有以下幾種。
· 直接將實體的持久化標識進行改變。
· 調用session.createQuery()方法。
· 調用session.getNameQuery()方法。
· 調用session.createFilter()方法。
· 調用session.createCriteria()方法。
· 調用session.createSQLQuery()方法。
(2)瞬時—持久化狀態的方法有以下幾種。
· 調用session.save()方法。
· 調用session.saveOrUpdate()方法。
(3)脫管—持久化狀態的方法有以下幾種。
· 調用session.load()方法。
· 調用session.lock()方法。
· 調用session.update()方法。
· 調用session.saveOrUpdate()方法。
(4)脫管—瞬時狀態的方法有以下幾種。
· 直接將實體的持久化標識清除。
· 調用session.delete()方法。
(5)持久化—脫管狀態的方法:關閉Hibernate Session。
(6)持久化—瞬時狀態的方法。調用session.delete()方法。
(7)脫管狀態-脫管狀態但影響數據庫記錄的方法:調用session.merger()方法。
摘自:http://book.csdn.net/bookfiles/563/10056318681.shtml