Hibernate01-入門

一、搭建Hibernate環境

1、Hibernate框架簡介

  • Hibernate是數據持久化工具,也是一個開放源代碼的ORM解決方案。Hibernate內部封裝了通過JDBC訪問數據庫的操作,向上層應用提供面向對象的數據訪問API。

  • Hibernate是ORM解決方案 :基於ORM,Hibernate在對象模型和關係數據庫的表之間建立了一座橋樑。通過Hibernate,程序員就不需要再使用sql語句操作數據庫中的表,而是使用API直接操作JavaBean對象就可以實現數據的存儲、查詢、更改和刪除等操作,顯著降低了由於對象與關係數據庫在數據表現方面的範例不匹配而導致的開發成本。

2、爲什麼選擇Hibernate框架

(1)Hibernate優點:

  • Hibernate功能強大,是Java應用於關係數據庫之間的橋樑,較之JDBC方式操作數據庫,代碼量大大減少,提高了持久化代碼的開發速度,降低了維護成本。

  • Hibernate支持許多面向對象的特性,如組合、繼承、多態等,使得開發人員不必在面向業務領域的對象模型和麪向數據庫的關係數據模型之間來回切換,方便開發人員進行領域驅動的面向對象的設計與開發。

  • 可移植性好。系統不會綁定在某個特定的關係型數據庫上,對於系統更換數據庫,通常只需要修改Hibernate配置文件即可正常運行。

  • Hibernate框架開源免費,可以在需要時研究源代碼,改寫源代碼,進行功能的定製,具有可擴展性。

(2)Hibernate缺點:

  • 不適合以數據爲中心大量使用存儲過程的應用。
  • 大規模的批量插入、修改和刪除不適合使用Hibernate。

3、Hibernate與MyBatis的對比

Hibernate與MyBatis都屬於ORM框架,爲數據層提供持久化操作的支持。

區別如下:

  • (1)相對於MyBatis的" SQL-Mapping" 的ORM實現,Hibernate的ORM實現更加完善,提供了對象狀態管理的功能。Hibernate對數據操作,針對的是Java對象,即使使用Hibernate的查詢語言(HQL語句),其書寫規則也是面向對象的。

  • (2)Hibernate與具體數據庫的關聯只需要在XML中配置即可,Hibernate開發者不需要關注SQL的生成與結果的映射,所有的HQL語句與具體使用的數據庫無關,便於修改,可移植性好。而MyBatis直接使用sql語句,不同數據庫之間可能會有差異,修改工作量大,可移植性差。

  • (3)由於直接使用sql語句,因此MyBatis的使用靈活性更高,而Hibernate對於關係模型設計不合理、不規範的系統則不適用。在不考慮緩存的情況下,MyBatis的執行效率也比Hibernate高一些。

4、搭建Hibernate環境

(1)下載jar文件

Hibernate所需jar文件如下:

  • antlr-2.7.6.jar 語法分析器
  • commons-collections-3.1.jar 各種集合類和集合工具類的封裝
  • dom4j-1.6.1.jar XML的讀寫
  • javassist-3.12.0.GA.jar 分析、編輯和創建Java字節碼的類庫
  • jta.1.1.jar Java事務API
  • slf4j-api-1.6.1.jar 日誌輸出
  • hibernate-jpa-2.0-api-1.0.0.Final.jar 提供對JPA(Java持久化API)規範的支持

(2)部署jar文件

在項目中引用下載好的hibernate3.jar、lib\required、lib\jpa目錄下的jar文件及
Oracle數據庫驅動jar文件。

(3)創建Hibernate配置文件 hibernate.cfg.xml

Hibernate配置文件主要用於配置數據庫連接和Hibernate運行時所需的各種特性。

在工程的src目錄下添加Hibernate配置文件(可在project\etc目錄下找到示例文件),默認文件名爲“hibernate.cfg.xml”。該文件需要配置數據庫連接信息和Hibernate的參數。

hibernate.cfg.xml配置文件如下:

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory>
		<!--數據庫url-->
		<property name="connection.url">
			jdbc:oracle:thin@localhost:1521:orcl
		</property>
		<!--數據庫用戶-->
		<property name="connection.username">scott</property>
		<!--數據庫用戶密碼-->
		<property name="connection.password">123456</property>
		<!--數據庫JDBC驅動-->
		<property name="connection.driver_class">
			oracle.jdbc.driver.OracleDriver
		</property>
		<!--每個數據庫都有其對應的方言(Dialect)以匹配其平臺特性-->
		<property name="dialect">
			org.hibernate.dialect.Oracle10gDialect
		</property>
		<!--指定當前session範圍和上下文-->
		<property name="current_session_context_class">
			thread
		</property>
		<!--是否將運行期生成的sql輸出到日誌以供調試-->
		<property name="show_sql">true</property>
		<!--是否格式化sql-->
		<property name="format_sql">true</property>
	</session-factory>
</hibernate-configuration>

說明:

  • connection.url:表示數據庫url。jdbc:oracle:thin@localhost:1521:orcl是Oracle數據庫的URL。其中jdbc:oracle:thin@是固定寫法,localhost是IP地址,1521是端口號,orcl是數據庫實例名。

  • connection.username:表示數據庫用戶名

  • connection.password:表示數據庫用戶密碼

  • connection.driver_class:表示數據庫驅動。
    oracle.jdbc.driver.OracleDriver是Oracle數據庫的驅動類。

  • dialect:用於配置Hibernate使用的數據庫類型。Hibernate支持幾乎所有的主流數據庫,包括Oracle、DB2、MS SQL Server和MySql等。org.hibernate.dialect.Oracle10gDialect指定當前數據庫類型是Oracle 10g 及以上版本。

  • current_session_context_class:指定
    org.hibernate.context.CurrentSessionContet.currentSession() 方法的Session由誰來跟蹤管理。thread指定Session由當前執行的線程來跟蹤管理。

  • show_sql:如果設置爲true,則程序運行時在控制檯輸出sql語句。

  • format_sql:如果設置爲true,則程序運行時在控制檯輸出格式化後的SQL語句。

注: 因爲Hibernate的配置屬性較多,可在hibernate-jpa-2.0-api-1.0.0.Final.jar的
documentation\manual\z-CN\pdf 目錄中查看hibernate_reference.pdf的第3章3.4節瞭解可選的配置屬性。

(4)創建持久化類和映射文件

持久化類是指其 實例狀態需要被Hibernate持久化到數據庫中的類。
在應用的設計中,持久化類通常對應需求中的業務實體。爲了在將持久化類用於數據傳輸等用途時能夠對其實例正確執行序列化操作,建議實現java.io.Serializable接口。

創建持久化類:Dept.java

package cn.demo.po;

import java.io.Serializable;
/**
 * 部門表
 */
public class Dept implements Serializable {

    /**
     * 部門編號
     */
    private Integer deptNo;

    /**
     * 部門名稱
     */
    private String dName;

    /**
     * 部門地區
     */
    private String loc;
    
	//省略getter/setter
}

注: Dept持久化類deptNo屬性,用來唯一標識Dept類的每個實例。deptNo屬性又稱爲id屬性。在Hibernate中,這個ID屬性被稱爲對象標識符,一個Dept實例和Dept表中的一條記錄對應。


創建映射文件: 告訴“Hibernate”,持久化類Dept映射到數據庫的哪個表,以及哪個屬性對應到數據庫表的哪個字段。
注: 在Hibernate中,映射文件通常與對應的持久化類同名,並以“.hbm.xml”作爲後綴。

Dept.hbm.xml如下

<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.demo.po.Dept" table="DEPT">
        <id name="deptNo" type="java.lang.Integer" column="DEPTNO">
            <generator class="assigned"/>
        </id>
        <property name="dName" type="java.lang.String" column="DNAME"/>
        <property name="loc" type="java.lang.String">
            <column name="LOC"></column>
        </property>
        
    </class>
</hibernate-mapping>

說明:

  • class元素:定義一個持久化類的映射信息。常用屬性如下:
    name:表示持久化類的全限定名
    table:表示持久化類對應的數據庫表名
    dynamic-update="true"屬性:作用是隻修改發生變化的屬性。

  • id元素:表示持久化類的OID和表的主鍵的映射。常用屬性如下:
    name:表示持久化類屬性的名稱,和屬性的訪問器相匹配
    type:表示持久化類屬性的類型
    column:表示持久化類屬性對應的數據庫表字段的名稱,也可在子元素column中指定。

  • generator元素:id元素的子元素,用於指定主鍵的生成策略。常用屬性及子元素如下:
    class屬性:用來指定具體主鍵生成策略
    param元素:用來傳遞參數。

  • 常用的主鍵生成策略如下:

在這裏插入圖片描述

  • property元素:定義持久化類中的屬性和數據庫表中的字段的對應關係。常用屬性如下:
    name:表示持久化類屬性的名稱,和屬性的訪問器相匹配。
    type:表示持久化類屬性的類型
    column:表示持久化類屬性對應的數據庫表字段的名稱,也可在子元素column中指定。

  • column元素: 用於指定其父元素代表的持久化類屬性所對應的數據庫表中的字段。常用屬性如下:
    name:表示字段的名稱
    length:表示字段的長度
    not-null:設定是否不能爲null,設置爲true表示爲不能爲null

映射文件定義完畢,還需要在配置文件hibernate.cfg.xml中聲明

<hibernate-configuration>
        <session-factory>
	<!--省略其他配置-->
	<!--映射文件配置,注意文件名必須包含其相對於classpath的全路徑-->
	<mapping resource="cn/demo/dao/Dept.hbm.xml"/>
        </session-factory>
</hibernate-configuration>

二、使用Hibernate API實現持久化操作

使用Hibernate操作數據庫包括7個步驟:使用Hibernate操作數據庫包括7個步驟:

  • (1)讀取並解析配置文件及映射文件
	Configuration conf=new Configuration().configure();

根據默認位置的Hibernate配置文件中的信息,構建Configuration對象。
Configuration對象負責管理Hibernate的配置信息。

  • (2)依據配置文件和映射文件中的信息,創建Sessionfactory對象
	SessionFactory sf=conf.buildSessionFactory();

Configuration對象會根據當前的數據庫配置信息,構造SessionFactory對象。SessionFactory對象一旦構造完畢,Configuration對象的任何變更將不會影響已經創建的SessionFactory對象。若Hibernate配置信息有改動,那麼需要基於改動後的Configuration對象重新創建一個SessionFactory對象。

(3)打開Session

	Session session=sf.getCurrentSession();	//或者使用sf.openSession();

SessionFactory對象負責創建Session對象。
Session是Hibernate持久化操作的基礎。Session作爲貫穿Hibernate的持久化管理器的核心,提供了衆多持久化方法,如save()、delete()、update()、 get()、 load()等。

(4)開始一個事務

	Transaction tx=session.beginTransaction();

(5)數據庫操作

	session.save(user);	//保存操作

(6)結束事務

	tx.commit();	//提交事務
	或
	tx.rollback();	//回滾事務

(7)如果是通過SessionFactory的openSession()方法獲取的Session對象,則需關閉session。

	session.close();

注: 若在Hibernate配置文件中將參數current_session_context_class設置爲thread,並採用SessionFactory的getCurrentSession()方法獲得Session對象,則不需要執行session.close()方法,因爲通過這種方式獲得的Session對象,會在關聯的事務結束(提交或回滾)時自動關閉。

補充: 在項目開發過程中,通常使用工具類來管理SessionFactory 和Session,下面創建HibernateUtil.java。


/**
 * 工具類:管理SessionFactory和Session
 */
public class HibernateUtil {


    private static Configuration configuration;
    private final static SessionFactory sessionFactory;

    //初始化Configuration和SessionFactory
    static{
        try{
            configuration=new Configuration().configure();
            sessionFactory=configuration.buildSessionFactory();
        }catch(HibernateException ex) {
            throw  new ExceptionInInitializerError(ex);
        }
    }

    //獲取session對象
    public static Session currentSession(){
        return  sessionFactory.getCurrentSession();
    }
}

說明:在此工具類中,採用SessionFactory的getCurrentSession()方法獲取Session對象,結合Hibernate配置文件中的以下配置:

	<property name="current_session_context_class">thread</property>

可以在多線程的應用環境中獲得線程安全的Session對象,在多線程情況下共享Session是不安全的,通過以上配置,在每個執行的線程中首次調用getCurrentSession()方法時,會爲該執行線程創建並保持一個Session對象。其後,該線程在執行中再次調用getCurrentSession()方法,只會返回和該線程綁定的那個Session對象,這就保證了每個執行線程都使用自己獨立的Session對象。


1、根據主鍵查詢

Hibernate提供了兩種方法根據主鍵加載對象:get()和load()

  • Object get(Class clazz,Serializable id);
  • Object loas(Class clazz,Serializable id);

例:


public class DeptDao {

	/**
     * 根據id獲取Dept對象:使用session.get()方式
     * 此種方式若數據表中沒有匹配的數據,則返回null
     * @param id
     * @return
     */
    public Dept get(Serializable id){
        //通過Session的get()方法根據OID加載指定對象
        return (Dept) HibernateUtil.currentSession().get(Dept.class,id);
    }

    /**
     * 根據id獲取Dept對象:使用session.load()方式
     * @param id
     * @return
     */
    public Dept load(Serializable id){
        //通過Session的get()方法根據OID加載指定對象
        return (Dept) HibernateUtil.currentSession().load(Dept.class,id);
    }
}

get()方法與load()方法區別:

  • 當使用Session的get()方法時,如果加載的數據不存在,則get()方法會返回null。
  • 當使用load()方法,若加載的數據不存在,則會拋出異常。

業務層DeptBiz.java代碼如下:

package cn.demo.service;

import cn.demo.dao.dept.DeptDao;
import cn.demo.po.Dept;
import cn.demo.utils.HibernateUtil;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Transaction;

import java.util.List;

public class DeptBiz {

    private DeptDao deptDao=new DeptDao();

    /**
     * 根據id獲取指定部門
     * @param id
     * @return
     */
    public Dept findDeptById(Integer id){
        Transaction tx=null;
        Dept result=null;
        try{
            tx= HibernateUtil.currentSession().beginTransaction();  //開啓事務
            result=deptDao.get(id);     //調用dao方法,根據OID加載指定Dept對象

            //result=deptDao.load(id);    //調用dao方法,根據OID加載指定Dept對象
            //輸出結果,與調用get()時不同,需在會話關閉前測試查詢結果
            System.out.println(result.getdName()+"----->deptName");

            tx.commit();
        }catch (HibernateException e){
            e.printStackTrace();
            if(tx!=null){
                tx.rollback();
            }
        }
        return result;
    }
}

測試類

package cn.demo.test.dept;

import cn.demo.po.Dept;
import cn.demo.po.Emp;
import cn.demo.service.DeptBiz;
import org.junit.Test;

import java.util.List;

public class DeptTest {

    /**
     * 測試獲取Dept對象
     */
    @Test
    public void test1(){
        //1.加載數據操作
        Dept dept=new DeptBiz().findDeptById(10);
        //2.輸出數據
        System.out.println(dept.getdName());
    }
}

運行結果
在這裏插入圖片描述

補充:爲了簡化編碼,再定義一個基類BaseDao,對獲取Session的方法進行封裝,在此基礎上,讓所有的Dao類繼承BaseDao。

public class BaseDao {

    /**
     * 獲取Session對象
     * @return
     */
    public Session currentSession(){
        return HibernateUtil.currentSession();
    }
}

2、使用Hibernate實現CRUD

  • demo1:使用Hibernate實現增加部門記錄

DeptDao.java


public class DeptDao extends BaseDao{

	  /**
     * 新增部門信息
     * @param dept
     */
    public void save(Dept dept){
        currentSession().save(dept);    //保存指定的Dept對象
    }

}

DeptBiz.java


public class DeptBiz{

	private DeptDao deptDao=new DeptDao();
	
	/**
     * 新增部門
     * @param dept
     */
    public void addNewDept(Dept dept){
        Transaction tx=null;
        try {
            tx=deptDao.currentSession().beginTransaction(); //開啓事務
            deptDao.save(dept);
            tx.commit();
        }catch (HibernateException e){
            e.printStackTrace();
            if(tx!=null){
                tx.rollback();
            }
        }
    }
}

測試類

   /**
     * 測試新增
     */
    @Test
    public void Test2(){
        Dept dept=new Dept();
        dept.setDeptNo(11);
        dept.setdName("質管部");
        dept.setLoc("西區");
        //保存新部門信息
        new DeptBiz().addNewDept(dept);
    }

執行結果:

在這裏插入圖片描述

  • demo2:使用Hibernate實現部門的修改和刪除

對於Hibernate這種ORM工具,操作都是針對對象的。要修改和刪除數據,首先要獲得數據,然後才能進行修改和刪除操作。

DeptDao.java

public class DeptDao extends BaseDao{

	/**
     * 根據id獲取Dept對象:使用session.load()方式
     * 若沒有獲取到數據,則會報異常
     * @param id
     * @return
     */
    public Dept load(Serializable id){
        //通過Session的get()方法根據OID加載指定對象
        return (Dept)currentSession().load(Dept.class,id);
    }
}

DeptBiz.java

public class DeptBiz{

	private DeptDao deptDao=new DeptDao();
	
	  /**
     * 修改部門信息
     * @param dept 修改後的部門信息
     */
    public void updateDept(Dept dept){
        Transaction tx=null;
        try {
            tx=deptDao.currentSession().beginTransaction(); //開啓事務
            //通過get()或load()方法加載要修改的部門對象
            Dept deptToUpdate=deptDao.load(dept.getDeptNo());
            //更新部門數據
            deptToUpdate.setdName(dept.getdName()); //修改部門名稱
            deptToUpdate.setLoc(dept.getLoc());     //修改地區
            tx.commit();
        }catch (HibernateException e){
            e.printStackTrace();
            if(tx!=null){
                tx.rollback();
            }
        }
    }
}

測試類:

	 /**
     * 更新部門信息
     */
    @Test
    public void test3(){
        Dept dept=new Dept();
        dept.setDeptNo(11);
        dept.setdName("質管部");
        dept.setLoc("東區");
        //更新部門信息
        new DeptBiz().updateDept(dept);
    }

測試結果:

在這裏插入圖片描述

  • demo3:實現刪除部門

DeptDao.java

public class DeptDao extends BaseDao {

    /**
     * 刪除部門
     * @param dept
     */
    public  void delete(Dept dept){
        currentSession().delete(dept);  //刪除指定的Dept對象
    }
}

DeptBiz.java


public class DeptBiz {

    private DeptDao deptDao=new DeptDao();
    
    /**
     * 刪除部門
     * @param id
     */
    public void deleteDept(Integer id){
        Transaction tx=null;
        try {
            tx=deptDao.currentSession().beginTransaction(); //開啓事務
            //通過get()或load()方法加載要修改的部門對象
            Dept deptToDelete=deptDao.load(id);
            deptDao.delete(deptToDelete);   //刪除部門數據
            tx.commit();
        }catch (HibernateException e){
            e.printStackTrace();
            if(tx!=null){
                tx.rollback();
            }
        }

    }
}

測試類

    /**
     * 測試刪除部門
     */
    @Test
    public  void test4(){
        new DeptBiz().deleteDept(11);
    }

運行結果:
在這裏插入圖片描述


三、Hibernate中Java對象的生命週期

1、Hibernate中持久化對象的生命週期

Hibernate框架通過Session來管理Java對象的狀態,在持久化生命週期中,Java對象存在以下3種狀態:

(1)瞬時狀態 Transient

瞬時狀態又稱臨時狀態。如果Java對象與數據庫中的數據沒有任何的關聯,即此Java對象在數據庫中沒有相關聯的記錄,此時Java對象的狀態爲瞬時狀態。Session對瞬時狀態的Java對象是一無所知的,當對象不再被其他對象引用時,它的所有數據也就丟失了,對象將會被Java虛擬機按照垃圾回收機制處理。

(2)持久狀態 Persistent

當對象與Session關聯,被Session管理時,它就處於持久狀態。處於持久狀態的對象擁有數據庫標識(數據庫中的主鍵值)。對象在與Session發生關聯的情況分爲2種:第一種情況,通過Session的查詢接口、get()或load()方法從數據庫中加載對象時,加載的對象是與數據庫表中的一條記錄關聯的,此時對象與加載它的Session發生關聯。第二種情況,對瞬時狀態的對象調用Session的save()、saveOrUpdate()等方法時,在保存對象數據的同時,Java對象也會與Session發生關聯。對於處於持久狀態的對象,Session會持續跟蹤和管理他們,如果對象的內部狀態發生了任何變更,Hibernate會選擇合適的時機(如事務提交時)將變更同步到數據庫中。

(3)遊離狀態 Detached
遊離狀態又稱脫管狀態。處於持久狀態的對象,脫離與其關聯的Session管理後,就處於遊離狀態。處於遊離狀態的對象,Hibernate無法保證對象所包含的數據與數據庫中的記錄一致,因爲Hibernate已經無法感知對該對象的任何操作。Session提供了update()、saveOrUpdate()等方法,將處於遊離狀態的對象的數據以更新的方式同步到數據庫中,並將該對象與當前的Session關聯。這時,對象的狀態就從遊離狀態重新轉換爲持久狀態。

2、使用Hibernate API轉換對象的狀態

(1)瞬時狀態轉爲持久狀態

創建一個部門對象,此時該對象與數據庫中的數據沒有任何關聯,所以處於瞬時狀態,當調用Session的save()、saveOrUpdate()等方法保存對象後,該對象即由瞬時狀態轉換爲持久狀態。

		Dept dept=new Dept();	
		//賦值
		dept.setDeptNo(1);
		dept.setDName("財務部");
		dept.setLoc("china");

使用Session的get()、 load() 方法獲取對象,該對象的狀態是持久狀態。

(2)持久狀態轉爲瞬時狀態

執行Session的delete()方法後,對象由原來的持久狀態變爲瞬時狀態,因爲此時該對象沒有與任何的數據庫數據關聯。

(3)持久狀態轉游離狀態

執行Session的evict()、clear()或close()方法,對象由原來的持久狀態轉爲遊離狀態。

  • Session.evict():會把指定的緩衝對象進行清除。
  • Session.clear():把緩衝區內的全部對象清除,但不包括操作中的對象。

(4)遊離狀態轉持久狀態

執行Session的update()或saveOrUpdate()方法後,對象由遊離狀態轉爲持久狀態,再次與當前Session相關聯。

例:

	//根據部門編號獲取部門對象
	Dept dept=deptDao.load(dept.getDeptNo);	
	//對該部門對象進行更新操作
	dept.setDName("財務部02");
	dept.setLoc("China");

(5)遊離狀態轉瞬時狀態

執行Session的delete()方法,對象由遊離狀態轉爲瞬時狀態。

注: 處於瞬時狀態或遊離狀態的對象不再被其他對象引用時,會被Java虛擬機按照垃圾回收機制處理。

四、Hibernate髒檢查及如何刷新緩存

1、什麼是髒檢查

在Hibernate中,數據前後發生變化的對象,稱爲髒對象。

例:

	tx=session.beginTransaction();
	//獲取部門對象,dept對象處於持久狀態
	Dept dept=(Dept)session.load(Dept.class,10);
	//修改後,部門信息和之前不同,此時dept對象稱爲所謂的“髒對象"
	dept.setDName("質管部");
	//提交事務
	tx.commit();

說明:

以上代碼中dept對象處於持久狀態,當dept對象被加入Session緩存中時,Session會爲dept對象的值類型的屬性複製一份快照。操作中,dname屬性發生改變,dept對象即成爲髒對象。在事務提交時,Hibernate會對Session中持久狀態的對象進行檢測,即比較dept對象的當前屬性與它的快照,以判斷dept對象的屬性是否發生了變化,這種判斷成爲髒檢查。如果對象發生了改變,則Session會根據髒對象的最新屬性值來執行相關的sql語句,將變化更新到數據庫,以確保內存中的對象數據與數據庫中的數據一致。

2、什麼是刷新緩存

Session是Hibernate嚮應用程序提供的持久化操縱的主要接口,它提供了基本的保存、更新、刪除和加載Java對象的方法。Session具有一個緩存,可以管理和跟蹤所有持久化對象。在某些時間點,Session會根據緩存中對象的變化來執行相關sql語句,將對象發生的變化同步到數據庫中,換句話就是將數據庫同步爲與Session緩存一致,這一過程稱爲刷新緩存。

3、Session如何刷新緩存

當Session緩存中對象的屬性發生變化時,Session並不會立即執行髒檢查和執行相關的sql語句,而是在特定的時間點,即刷新緩存時才執行。這使得Session能夠把多次變化合併爲一條或者一批sql語句,減少了訪問數據庫的次數,從而提高了應用程序的數據訪問性能。在默認情況下,Session會在以下時間點刷新緩存:

  • (1)應用程序顯式調用Session的flush()方法時。

    Session的flush()方法進行刷新緩存的操作,會觸發髒檢查,視情況執行相關的sql語句。

  • (2)應用程序調用Transaction的commit()方法時。

    commit()方法會先調用Session的刷新緩存方法flush(),然後向數據庫提交事務。在提交事務時執行刷新緩存的動作,可以減少訪問數據庫的頻率,儘可能縮短當前事務對數據庫中相關資源的鎖定時間。

五、使用Hibernate API 更新數據

Hibernate中的Session提供了多種更新數據的方法,如Update()、saveOrUpdate()、merge()方法。

  • (1)update()方法
    用於將遊離狀態的對象恢復爲持久狀態,同時進行數據庫更新操作。
    當參數對象的OID爲null時會報異常。

  • (2)saveOrrUpdate()方法
    同時包含了save()與update()方法的功能,如果傳入參數是瞬時狀態的對象,就調用save();如果傳入參數是遊離狀態的對象,則調用update()方法。

  • (3)merge()方法
    能夠把作爲參數傳入的遊離狀態對象的屬性複製到一個擁有相同的OID的持久狀態對象中,通過對持久狀態對象的髒檢查實現更新操作,並返回該持久狀態對象;如果無法從Session緩存或數據庫中加載到相應的持久狀態對象,即傳入的是瞬時對象,則創建其副本執行插入操作,並返回這一新的持久狀態對象。無論何種情況,傳入對象的狀態都不受影響。

demo4:演示使用merge()方法進行修改操作

Dept.hbm.xml文件

<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.bdqn.po.Dept" table="DEPT" schema="scott" dynamic-update="true">
        <id name="deptNo" type="java.lang.Integer" column="DEPTNO">
            <!--爲了避免主鍵生成器assigned造成的干擾,把主鍵生成器 替換爲increment-->
            <generator class="increment"/>
        </id>
        <property name="dName" type="java.lang.String" column="DNAME"/>
        <property name="loc" type="java.lang.String">
            <column name="LOC"></column>
        </property>        
    </class>
</hibernate-mapping>

DeptDao.java

	 /***
     * 使用Hibernate API merge()方法實現更新操作
     * @param dept
     * @return
     */
    public  Dept merge(Dept dept){
        return (Dept)currentSession().merge(dept);
    }

DeptBiz.java


    /**
     * 調用merge()修改部門信息
     * @param dept
     * @return
     */
    public Dept mergeDept(Dept dept){
        Transaction tx=null;
        Dept persistentDept=null;   //持久化Dept對象
        try{
            tx=deptDao.currentSession().beginTransaction(); //開啓事務
            persistentDept=deptDao.merge(dept);
            tx.commit();
        }catch (HibernateException e){
            e.printStackTrace();
            if(tx!=null){
                tx.rollback();
            }
        }

        return persistentDept;
    }

測試類:

    /**
     * 調用merge()方法進行更新操作
     */
    @Test
    public void test5(){
        Dept dept=new Dept();
        //dept.setDeptNo(11); //遊離狀態,去調本行代碼則爲臨時狀態
        dept.setdName("開發部1");
        dept.setLoc("西區");
        //合併遊離狀態dept的數據或者保存臨時狀態的dept的副本
        new DeptBiz().mergeDept(dept);
    }

小結:如果當前Session緩存中沒有包含具有相同的OID的持久化對象,可以使用update()或saveOrUpdate()方法;若想隨時合併對象的修改而不考慮Session緩存中對象的狀態,可以使用merge()方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章