Hibernate——Hibernate核心類和接口

Hibernate核心類和接口

Configuration類

  1. 負責管理Hibernate的配置信息
  2. 讀取hibernate.cfg.xml文件
  3. 加載hibernate.cfg.xml配置文件中配置的驅動,url,用戶名,密碼,連接池
  4. 管理 *.hbm.xml對象關係文件

hibernate.cfg.xml文件

  1. 該文件用於指定各個參數,是hibernate的核心文件
  2. 默認放在src目錄下,也可以放在別的目錄下
  3. 指定連接數據庫的驅動、用戶名、密碼、url、連接池
  4. 指定對象關係映射文件的位置
  5. 也可以使用hibernate.properties文件來代替該文件(推薦使用hibernate.cfg.xml)

對象關係映射文件(*.hbm.xml)

  1. 該文件主要作用是建立表和類的映射關係,是不可或缺的重要文件
  2. 一般放在其映射的類的同一個目錄下,但不是必須的
  3. 命名方式一般是:類名.hbm.xml,但不是必須的
  4. 示意圖如下:

這裏寫圖片描述

SessionFactory(會話工廠)接口

  1. 緩存SQL語句和某些數據(Session級緩存)
  2. 在應用程序初始化的時候創建,是一個重量級的類(吃內存),一般用單例模式保證一個應用中只需要一個SessionFactory實例
  3. 如果某個應用訪問多個數據庫,則要創建多個會話工廠實例,一般是一個數據庫對應一個會話工廠實例
  4. 通過SessionFactory接口可以獲得Session(會話)實例

Session(會話)接口

  1. Session一個實例代表與數據庫的一次操作(當然一次操作可以使CRUD組合)
  2. Session實例通過SessionFactory獲取,用完需要關閉
  3. Session是線程不同步的(不安全),因此要保證在同一個線程中使用,可以用getCurrentSession()
  4. Session可以看做是持久化管理器,它是與持久化操作相關的接口

這裏討論一下通過SessionFactory獲取Session的兩個方法,openSession()getCurrentSession()的區別:

(1) 採用getCurrentSession()創建的Session會綁定到當前線程中,而採用openSession()創建的Session則不會

(2) 採用getCurrentSession()創建的Session在commit或rollback時會自動關閉,而採用openSession()創建的Session必須手動關閉。

(3) 如果是通過getCurrentSession()獲取Session,進行查詢也需要通過事務提交

(4) 如果希望使用getCurrentSession(),我們需要在hibernate.cfg.xml文件中加入如下配置:

(1)如果使用的是本地事務(jdbc事務)

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

(2)如果使用的是全局事務(jta事務)

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

本地事務:針對一個數據庫的事務

全局事務:跨數據庫的事務(比如銀行的跨行轉賬)


openSession()和getCurrentSession()究竟使用哪一個?原則是:

  1. 如果需要在同一線程中,保證使用同一個Session,則使用getCurrentSession()

  2. 如果在一個線程中,需要使用不同的Session,則使用openSession()

這裏我們可以改進我們的入門案例,增加HibernateUtil類,使用ThreadLocal(線程局部變量模式)將Session與線程關聯起來。

ackage com.gavin.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static SessionFactory sessionFactory = null;

    // 用ThreadLocal模式(線程局部變量模式)管理Session
    private static ThreadLocal<Session> threadLocal = new ThreadLocal<>();

    private HibernateUtil(){}

    static{
        sessionFactory = new Configuration().configure().buildSessionFactory();
    }

    /**
     * 獲取全新的Session
     * @return
     */
    public static Session openSession(){
        return sessionFactory.openSession();
    }

    /**
     * 獲取和線程關聯的session
     * @return
     */
    public static Session getCurrentSession(){
        Session session =  threadLocal.get();
        if (session == null) {
            session = sessionFactory.openSession();
            // 把session對象設置到threadLocal
            // 相當於該session已經和線程綁定
            threadLocal.set(session);
        }
        return session;
    }
}

openSession()和getCurrentSession()深入討論

在SessionFactory啓動的時候,Hibernate會根據配置創建相應的CurrentSessionContext,在getCurrentSession()被調用的時候,實際執行的方法是CurrentSessionContext.currentSession()。在currentSession執行時,如果當前Session爲空,currentSession會調用SessionFactory的openSession()


Session接口的幾個重要方法:

(1) 保存一個對象(記錄):——save方法

(2) 刪除一個對象(記錄):——delete方法

(3) 查詢一個對象(記錄):——get/load方法

(4) 修改一個對象(記錄):——update方法


get()和load()方法的區別:

(1) get()方法直接返回實體類,如果查不到數據則返回nullload()會返回一個實體代理對象(當前這個對象可以自動轉化爲實體對象),但當代理對象被調用時,如果數據不存在,就會拋出個org.hibernate.ObjectNotFoundException異常

(2) load()方法先到緩存(session緩存/二級緩存)中去查,如果沒有則返回一個代理對象(不馬上到DB中去找),等後面使用這個代理對象操作的時候,纔到DB中查詢,這就是我們常說的load在默認情況下支持延遲加載(lazy)

(3) get()先到緩存(session緩存/二級緩存)中去查,如果沒有就到DB中去查(即馬上發出sql語句)。總之,如果你確定DB中有這個對象就用load(),不確定就用get()(這樣效率高)

(4) 通過修改配置文件我們可以取消懶加載。–> 在對象關係映射文件中的class結點配置:lazy=”false”

Hibernate緩存的原理

Hibernate緩存分兩級。通過緩存可以有效減少對數據庫的頻繁查詢,提高性能。

Transaction(事務)接口

這裏簡單說明一些什麼是事務:事務簡單的說,就是一組對數據庫的操作集合,它們要麼全部成功,要麼全部失敗,這個保證數據的一致性,事務具有原子性。

  1. Transaction是底層的事務實現中抽象出來的接口
  2. 可能是一個JDBC或者JTA事務,這樣有利於Hibernate在不同執行環境的移植
  3. Hibernate要求顯示的調用事務(如果僅僅是查詢則可以不調用)

Query接口

Query接口類型的對象可以對數據庫操作,它可以使用HQL,QBC,QBE和原生SQL對數據庫操作。官方推薦使用HQL語句。

舉例:通過用戶名查詢數據:

public static void queryByName(String name){
   Session session = HibernateUtil.getCurrentSession();
   Transaction transaction = null;
   try {
       transaction = session.beginTransaction();
       // 獲取Query引用[這裏的Employee不是指的表,而是domain類名]
       Query query = session.createQuery("from Employee where name = '" + name + "'");
       // 通過list方法獲取結果,這個list會自動地將結果封裝成對應的domain對象類型
       List<Employee> list = query.list();
       list.forEach(e -> System.out.println("e = " + e));
       transaction.commit();
   }catch (Exception e){
       if (transaction != null) {
           transaction.rollback();
       }
       throw new RuntimeException(e);
   }finally {
       if (session != null && session.isOpen()) {
           session.close();
       }
   }
}

Criteria接口

Criteria接口也可用於面向對象方式的查詢,關於它的具體用法這裏先不做介紹。簡單看幾個案例:

  1. 最簡單案例,返回50條記錄
Criteria crit = session.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
  1. 限制結果集內容:
List cats = session.createCriteria(Cat.class).add(Restrictions.like("name", "Fritz%")).add(Restrictions.between("weight", "minWeight", "maxWeight")).lsit();
  1. 測試代碼如下:
public static void testCriteria(){
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = null;
    try {
        transaction = session.beginTransaction();
        Criteria criteria = session.createCriteria(Employee.class).setMaxResults(2).addOrder(Order.desc("id"));
        List<Employee> list = criteria.list();
        list.forEach(e -> System.out.println("e = " + e));
        transaction.commit();
    }catch (Exception e){
        if (transaction != null) {
            transaction.rollback();
        }
        throw new RuntimeException(e);
    }finally {
        if (session != null && session.isOpen()) {
            session.close();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章