一、持久化對象的狀態(tài)
1.瞬時對象(Transient Objects)
或臨時對象省有,使用new操作符初始化的對象不是立刻就持久化的硬梁。它們的狀態(tài)是瞬時的跃脊,也就是說它們沒有任何跟數(shù)據(jù)庫表相關(guān)聯(lián)的行為,只要應(yīng)用不再引用這些對象(不再被任何其它對象所引用)捧书,它們的狀態(tài)將會丟失吹泡,并由垃圾回收機制回收。沒有納入Session的管理鳄厌。2.持久化對象(Persistent Objects)
持久化實例是任何具有數(shù)據(jù)庫標識的實例荞胡。它有持久化管理器Session統(tǒng)一管理,持久化實例是在事務(wù)中進行操作的-它們的狀態(tài)在事務(wù)結(jié)束時同數(shù)據(jù)庫集進行同步了嚎。當事務(wù)提交時泪漂,通過執(zhí)行sql的insert、update和delete語句把內(nèi)存中的狀態(tài)同步到數(shù)據(jù)庫中歪泳。納入到Session的管理萝勤,在清零緩存(臟數(shù)據(jù)檢查)的時候,會和數(shù)據(jù)庫同步呐伞。3.離線對象(Detached Objects)
Session關(guān)閉后敌卓,持久化對象就變成離線對象。離線表示這個對象不能再與數(shù)據(jù)庫保持同步伶氢,它們不再受Hibernate管理趟径。在數(shù)據(jù)庫中有與之匹配的數(shù)據(jù)(和瞬時對象的主要區(qū)別,如瞬時對象就不能進行如updata操作)癣防,但是沒有納入Session的管理蜗巧。
示例:(工程hibernate_session
)
由于Session對象是一個重量級對象,所以我們采用單例模式:
HibernateUtils.java
package cn.itcast.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory factory;
static{
try{
//讀取配置文件
Configuration cfg = new Configuration().configure();
//初始化SessionFactory
factory = cfg.buildSessionFactory();
}catch(Exception e){
e.printStackTrace();
}
}
public static SessionFactory getSessionFactory(){
return factory;
}
public static Session getSession(){
//Session由工廠產(chǎn)生
return factory.openSession();
}
public static void closeSession(Session session){
if(session != null){
if(session.isOpen()){
session.close();
}
}
}
}
其他文件和上個例子基本一樣蕾盯,我們在這里新建一個數(shù)據(jù)庫hibernate_session
幕屹,然后使用類ExportDB.java
自動生成數(shù)據(jù)庫表。
測試:
SessionTest.java
package junit.test;
import java.util.Date;
import java.util.UUID;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.model.User;
import cn.itcast.util.HibernateUtils;
public class SessionTest {
@Test
public void testSave1(){
Session session = null;
Transaction transaction = null;
User user = null;
try{
//得到Session
session = HibernateUtils.getSession();
//開啟事務(wù)
transaction = session.beginTransaction();
//Transient狀態(tài)(臨時狀態(tài))
user = new User();
user.setId(UUID.randomUUID().toString());
user.setName("zhang");
user.setPassword("1111");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//persistent狀態(tài),當屬性發(fā)生改變的時候望拖,hibernate會自動和數(shù)據(jù)庫同步
session.save(user);
user.setName("tom");
session.update(user);
transaction.commit();
}catch(Exception e){
e.printStackTrace();
transaction.rollback();
}finally{
HibernateUtils.closeSession(session);
}
//detached狀態(tài)(離線狀態(tài))
user.setName("jack");
try{
session = HibernateUtils.getSession();
session.beginTransaction();
//persistent狀態(tài)
session.update(user);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
說明:可以看到當執(zhí)行save方法之后對象變?yōu)榱藀ersistent狀態(tài)渺尘,此時會發(fā)出insert語句,同時此時的狀態(tài)下说敏,如果我們修改對象鸥跟,在提交事務(wù)的時候會清理緩存(或叫臟數(shù)據(jù)檢查),會將新的對象存到數(shù)據(jù)庫中盔沫,發(fā)出update語句锌雀。而當Session關(guān)閉之后,對象變成了離線狀態(tài)迅诬,此時如果我們想修改數(shù)據(jù)庫中對象的值腋逆,那么需要重新獲取Session并開啟事務(wù),最后提交侈贷。
測試get方法:
@Test
public void testReadByGetMethod1(){
Session session = null;
try{
session = HibernateUtils.getSession();
session.beginTransaction();
//會立即發(fā)出查詢語句惩歉,加載User對象,此時對象是persistent狀態(tài)
User user = (User) session.get(User.class, "61bb68a4-5835-4825-8fa5-a93c41f2987f");
System.out.println("user.name = " + user.getName());
//persistent狀態(tài)下改變對象會自動和數(shù)據(jù)庫同步
user.setName("tom");
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
說明:其中g(shù)et方法的第二個參數(shù)是上個測試例子中存入數(shù)據(jù)的id俏蛮,試驗可知撑蚌,當使用get方法時會立即發(fā)出查詢語句,對象稱為persistent狀態(tài)搏屑,此時改變對象會在事務(wù)提交的時候清理緩存争涌,發(fā)出修改語句。但是辣恋,如果我們給出的id號在數(shù)據(jù)庫中不存在亮垫,那么get方法返回null。
測試load方法:
@Test
public void testReadByLoadMethod1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
//執(zhí)行l(wèi)oad方法時不會立即發(fā)出查詢語句伟骨,而是在要使用此對象的時候才會發(fā)出饮潦,比如下面的打印語句
//因為load方法實現(xiàn)了lazy方法(懶加載或延遲加載)
User user = (User) session.load(User.class, "61bb68a4-5835-4825-8fa5-a93c41f2987f");
//執(zhí)行下面這條語句的時候才會發(fā)出查詢語句
System.out.println("user.name = " + user.getName());
user.setName("jack");
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
說明:這里要注意load方法和get方法的區(qū)別,load方法采用的是延遲加載携狭,只有當要使用對象的時候才會去數(shù)據(jù)庫中查詢继蜡。同時如果我們給出的id號在數(shù)據(jù)庫中不存在,則會拋出ObjectNotFoundException
異常逛腿。
測試update方法:
@Test
public void testUpdate1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
//手動構(gòu)造的detached對象
User user = new User();
user.setId("61bb68a4-5835-4825-8fa5-a93c41f2987f");
user.setName("德華");
user.setPassword("2222");
session.update(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
說明:手動構(gòu)造detached狀態(tài)對象時我們給出的id必須是數(shù)據(jù)庫中存在的稀并,不然會拋出異常。同時表明detached對象可以update单默。雖然這里的對象是我們new出來的碘举,但是在數(shù)據(jù)庫中是有與之對應(yīng)的主鍵的,所以是detached狀態(tài)對象雕凹。
測試delete方法:
@Test
public void testDelete1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User) session.load(User.class, "61bb68a4-5835-4825-8fa5-a93c41f2987f");
session.delete(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
//刪除之后稱為Transient狀態(tài)
}
說明:這里我們可以看到從數(shù)據(jù)庫中刪除數(shù)據(jù)之后對象成為了Transient狀態(tài)殴俱。本來對象是persistent狀態(tài),刪除之后就變?yōu)門ransient狀態(tài)枚抵。
最后:
- get和load方法的區(qū)別是get不支持lazy线欲,而load支持;采用get加載數(shù)據(jù)汽摹,如果沒有與之匹配的數(shù)據(jù)返回null李丰,而load則拋出異常。
- Transient狀態(tài)的特征是:在數(shù)據(jù)庫中沒有與之匹配的數(shù)據(jù)逼泣,沒有納入Session的管理趴泌。
- detached的特征是:在數(shù)據(jù)庫中有與之匹配的數(shù)據(jù),也沒有納入Session的管理拉庶。
- get和load方法都只能根據(jù)主鍵進行查詢嗜憔,即單一查詢。
二氏仗、Query接口入門
我們可以使用Query接口發(fā)送hql語句進行查詢吉捶。
QueryTest.java
package junit.test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Test;
import cn.itcast.model.User;
import cn.itcast.util.HibernateUtils;
public class QueryTest {
@Test
public void testQuery(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Query query = session.createQuery("from User");
//查詢從哪里開始
query.setFirstResult(0);
//查詢出多少條數(shù)據(jù)
query.setMaxResults(2);
//查詢出的數(shù)據(jù)Query接口會自動幫我們存入到一個List集合中
List<User> list = query.list();
for(User user : list){
System.out.println(user.getId());
System.out.println(user.getName());
}
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
說明:這里我們可以使用hql語句將所有數(shù)據(jù)都查詢出來,同時還可以進行分頁皆尔,對于hql語句呐舔,它是針對對象的查詢語句,所以對于對象名是區(qū)分大小寫的慷蠕。查詢出來都 數(shù)據(jù)Query接口會自動幫我們存入到一個List集合中珊拼。在后面我們還會詳細說明。