Hibernate 框架入門

1、Hibernate框架介紹

什麼是Hibernatejava

咱們能夠從度娘上摘抄這樣有關Hibernate的介紹:mysql

Hibernate是一個開放源代碼的對象關係映射框架,它對JDBC進行了很是輕量級的對象封裝,它將POJO與數據庫表創建映射關係,是一個全自動的orm框架,hibernate能夠自動生成SQL語句,自動執行,使得Java程序員能夠爲所欲爲的使用對象編程思惟來操縱數據庫。Hibernate能夠應用在任何使用JDBC的場合,既能夠在Java的客戶端程序使用,也能夠在Servlet/JSP的Web應用中使用。程序員

從中,咱們能夠得出這樣的結論:Hibernate是一個輕量級的JDBC封裝,也就是說,咱們可使用Hibernate來完成原來咱們使用JDBC完成的操做,也就是與數據庫的交互操做。它是在dao層去使用的。web

什麼是ORMsql

對象關係映射(英語:Object Relation Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程序技術,用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換。 數據庫

對象-關係映射,是隨着面向對象的軟件開發方法發展而產生的。面向對象的開發方法是當今企業級應用開發環境中的主流開發方法,關係數據庫是企業級應用環境中永久存放數據的主流數據存儲系統。對象和關係數據是業務實體的兩種表現形式,業務實體在內存中表現爲對象,在數據庫中表現爲關係數據。內存中的對象之間存在關聯和繼承關係,而在數據庫中,關係數據沒法直接表達多對多關聯和繼承關係。所以,對象-關係映射(ORM)系統通常以中間件的形式存在,主要實現程序對象到關係數據庫數據的映射。 編程

ORM模型的簡單性簡化了數據庫查詢過程。使用ORM查詢工具,用戶能夠訪問指望數據,而沒必要理解數據庫的底層結構。 小程序

這裏寫圖片描述

簡單來講,咱們使用ORM能夠將咱們的對象(或類)去進行映射,使得咱們能夠去操做對象就能完成對錶的操做。安全

爲何使用Hibernate框架session

緣由以下:

  • Hibernate對JDBC訪問數據庫的代碼作了封裝,大大簡化了數據訪問層繁瑣的重複性代碼。
  • Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現,它很大程度的簡化了dao層編碼工做。

總結:Hibernate是企業級開發中的主流框架,映射的靈活性很出色。它支持不少關係型數據庫。

Hiberate框架學習目標

因爲以前學過Hiberate框架,因此這就等因而在複習了。對於Hiberate框架的學習重點,能夠總結爲:

  • 掌握Hiberate的基本配置——即搭建Hiberate開發環境
  • 掌握Hiberate經常使用API——即如何使用Hiberate框架進行開發
  • 掌握Hiberate的關聯映射——解決表與表之間存在的關係問題,有1:n(一對多)、 1:1(一對一)、m:n(多對多)關係
  • 掌握Hiberate的檢索方式——即掌握Hiberate的查詢
  • 掌握Hiberate的優化方式——即提升Hiberate的效率

2、Hibernate的體系結構與開發步驟

Hibernate的體系結構:

這裏寫圖片描述

Hibernate開發步驟:

  • 建立持久化類
  • 建立對象-關係映射文件
  • 建立Hibernate配置文件
  • 經過Hibernate API編寫訪問數據庫的代碼

這裏寫圖片描述

3、第一個Hibernate程序

介紹完Hibernate框架以後,咱們來快速入門Hibernate,對其有一個直觀的瞭解。

下載Hibernate

可去官網下載Hibernate,我下載的是

這裏寫圖片描述

因此,以後有關Hibernate的系列文章都是以這個版本爲藍圖展開的。下載解壓縮以後,能夠看到以下目錄結構:

這裏寫圖片描述

其中,在lib/required目錄下,包含運行Hibernate項目必須的jar包有:

這裏寫圖片描述

建立數據庫與表

正如前面所說,Hibernate是一個輕量級的JDBC封裝,也就是說,咱們可使用Hibernate來完成原來咱們使用JDBC完成的操做,也就是與數據庫的交互操做。因此咱們首先要建立數據庫與表,這裏我使用的數據庫是mysql。

create database hibernateTest;
use hibernateTest;
create table t_customer( id int primary key auto_increment, name varchar(20), address varchar(50) );

建立實體類

首先在Eclipse上建立一個Dynamic Web Project,好比我建立的是hibernate_demo1,而後再切到Java透視圖。這兒咱們在cn.itheima.domain包中建立一個實體類——Customer.java。

public class Customer {

    private int id;
    private String name;
    private String address;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "Customer [id=" + id + ", name=" + name + ", address=" + address + "]";
    }   
}

導入Hibernate框架相關依賴jar包

首先導入lib/required目錄下全部的jar包:

這裏寫圖片描述

再導入mysql數據庫的驅動jar包:

這裏寫圖片描述

最後導入日誌相關的jar包:

這裏寫圖片描述

導入完日誌相關的jar包以後,咱們還須將project/etc/log4j.properties文件導入到工程hibernate_demo1的src目錄下,這樣工程的整個結構就爲:

這裏寫圖片描述

Hibernate的相關配置文件

準備好以上工做以後,咱們終於要踏入Hibernate的學習中了。首先咱們要編寫Hibernate的相關配置文件,Hibernate的相關配置文件分爲兩種:

  • xxx.hbm.xml:它主要是用於描述類與數據庫中的表的映射關係。
  • hibernate.cfg.xml:它是Hibernate框架的核心配置文件。

有關這兩個配置文件的詳細介紹,咱們後面會給你們講解,若是就在這裏弄的話,違背了個人初衷了,本文只是在教初學者怎樣快速入門Hibernate。

映射配置文件

首先咱們要學會如何編寫映射配置文件,你們要知道編寫完的映射配置文件應與實體類在同一個包下,而且名稱應是類名.hbm.xml,因此咱們要在cn.itheima.domain包下建立一個Customer.hbm.xml文件,可是它的約束應該怎麼寫呢?能夠在Hibernate的核心jar包——hibernate-core-5.0.7.Final.jar的org.hibernate包下查找到hibernate-mapping-3.0.dtd文件,打開該文件,找到以下內容:

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

而後複製黏貼到Customer.hbm.xml文件中。
這裏我先給出Customer.hbm.xml文件的內容,但內容不作過多介紹:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itheima.domain">
    <!-- name:即實體類的全名 table:映射到數據庫裏面的那個表的名稱 catalog:數據庫的名稱 -->
    <class name="Customer" table="t_customer" catalog="hibernateTest">
        <!-- class下必需要有一個id的子元素 -->
        <!-- id是用於描述主鍵的 -->
        <id name="id" column="id">
            <!-- 主鍵生成策略 -->
            <generator class="native"></generator>
        </id>
        <!-- 使用property來描述屬性與字段的對應關係 若是length忽略不寫,且你的表是自動建立這種方案,那麼length的默認長度是255 -->
        <property name="name" column="name" length="20"></property>
        <property name="address" column="address" length="50"></property>
    </class>
</hibernate-mapping>

核心配置文件

核心配置文件主要是Hibernate框架所使用的,它主要包含了鏈接數據庫的相關信息和Hibernate的相關配置等。
如今咱們要學會如何編寫Hibernate核心配置文件,你們也要知道編寫完的核心配置文件應在src目錄下,而且名稱應是hibernate.cfg.xml,因此咱們要在src目錄下建立一個hibernate.cfg.xml文件,可是它的約束應該怎麼寫呢?能夠在Hibernate的核心jar包——hibernate-core-5.0.7.Final.jar的org.hibernate包下查找到hibernate-configuration-3.0.dtd文件,打開該文件,找到以下內容:

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

而後複製黏貼到hibernate.cfg.xml文件中。
在這個文件中到底如何配置暱?咱們能夠參考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件。這裏我先給出hibernate.cfg.xml文件的內容,但內容不作過多介紹:

<?xml version="1.0" encoding="UTF-8"?>
<!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>
        <!-- 配置關於數據庫鏈接的四個項:driverClass url username password -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///hibernateTest</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">yezi</property>

        <!-- 能夠將向數據庫發送的SQL語句顯示出來 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 格式化SQL語句 -->
        <property name="hibernate.format_sql">true</property>

        <!-- hibernate的方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 配置hibernate的映射文件所在的位置 -->
        <mapping resource="cn/itheima/domain/Customer.hbm.xml" />
    </session-factory>
</hibernate-configuration>

Hibernate快速入門開發測試

在cn.itheima.test包下建立一個單元測試類——HibernateTest1.java。

public class HibernateTest1 {

    // 保存一個Customer
    @Test
    public void saveCustomerTest() {
        // 建立一個Customer
        Customer c = new Customer();
        c.setName("葉子");
        c.setAddress("武漢");

        // 使用Hibernate的API來完成將Customer信息保存到mysql數據庫中的操做
        Configuration config = new Configuration().configure(); // Hibernate框架加載hibernate.cfg.xml文件
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession(); // 至關於獲得一個Connection
        // 開啓事務
        session.beginTransaction();

        // 操做
        session.save(c);

        // 事務提交
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }

    // 根據id查詢一個Customer對象
    @Test
    public void findCustomerByIdTest() {
        Configuration config = new Configuration().configure(); // Hibernate框架加載hibernate.cfg.xml文件
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession(); // 至關於獲得一個Connection
        // 開啓事務
        session.beginTransaction();

        // 根據業務來編寫代碼
        // Customer c = session.get(Customer.class, 1);
        Customer c = session.load(Customer.class, 1);

        System.out.println(c.getName());

        // 事務提交
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }

    // 修改操做
    @Test
    public void updateCustomerTest() {
        Configuration config = new Configuration().configure(); // Hibernate框架加載hibernate.cfg.xml文件
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession(); // 至關於獲得一個Connection
        // 開啓事務
        session.beginTransaction();

        // 根據業務來編寫代碼
        Customer c = session.get(Customer.class, 1);
        c.setName("鄭敏");
        session.update(c); // 修改操做

        // 事務提交
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }

    // 刪除操做---根據id進行刪除
    @Test
    public void deleteCustomerTest() {
        Configuration config = new Configuration().configure(); // Hibernate框架加載hibernate.cfg.xml文件
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession(); // 至關於獲得一個Connection
        // 開啓事務
        session.beginTransaction();

        // 根據業務來編寫代碼
        Customer c = session.get(Customer.class, 1);
        session.delete(c); // 刪除操做

        // 事務提交
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }

    // 查詢全部Customer
    @Test
    public void findAllCustomerTest() {
        Configuration config = new Configuration().configure(); // Hibernate框架加載hibernate.cfg.xml文件
        SessionFactory sessionFactory = config.buildSessionFactory();
        Session session = sessionFactory.openSession(); // 至關於獲得一個Connection
        // 開啓事務
        session.beginTransaction();

        // 根據業務來編寫代碼
        Query query = session.createQuery("from Customer"); // HQL語句,它相似於SQL語句
        List<Customer> list = query.list();
        System.out.println(list);

        // 事務提交
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }

}

測試如若都無任何問題,則咱們就算入門Hibernate了。

Hibernate執行原理總結

可從度娘上摘抄到以下文字:

  • 經過Configuration().configure();讀取並解析hibernate.cfg.xml配置文件。
  • 由hibernate.cfg.xml中的讀取解析映射信息。
  • 經過config.buildSessionFactory();獲得sessionFactory。
  • sessionFactory.openSession();獲得session。
  • session.beginTransaction();開啓事務。
  • persistent operate; 執行你本身的操做。
  • session.getTransaction().commit();提交事務。
  • 關閉session。
  • 關閉sessionFactory。

4、第二個Hibernate程序——完整的數據庫操做(CRUD)

前面咱們寫了一個Hibernate入門的小程序。如今咱們來寫第二個Hibernate程序——實現對數據庫完整的操做(CRUD)。

咱們首先建立一個工具類——HibernateUtils.java,該工具類的做用專門用來獲取全局惟一的SessionFactory,以及從全局惟一的SessionFactory中打開一個Session。

public class HibernateUtils {

    // SessionFactory全局只須要有一個就能夠了,由於它的建立和銷燬須要消耗大量的資源,初始化信息會比較多,而且它是線程安全的,能夠在多線程的環境下使用它
    private static SessionFactory sessionFactory;

    static {
        // 初始化SessionFactory方式一:
        /* Configuration cfg = new Configuration(); // 表明配置文件的一個對象 cfg.configure(); // 讀取默認的配置文件(hibernate.cfg.xml) // cfg.configure("hibernate.cfg.xml"); // 讀取指定位置的配置文件 sessionFactory = cfg.buildSessionFactory(); */

        // 初始化SessionFactory方式二:
        sessionFactory = new Configuration() //
                .configure() //
                .buildSessionFactory(); // 方法鏈
    }

    /** * 獲取全局惟一的SessionFactory * * @return */
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /** * 從全局惟一的SessionFactory中打開一個Session * * @return */
    public static Session openSession() {
        return sessionFactory.openSession();
    }

}

思考一個問題,若咱們要編寫代碼實現對數據庫完整的操做,那麼就一定涉及到分頁查詢,要實現分頁查詢,咱們必定要弄清楚分頁設計結構圖。因此咱們還要建立一個類——QueryResult.java,用於封裝查詢結果。

public class QueryResult {

    private int count; // 總記錄數
    private List list; // 一頁的數據

    public QueryResult(int count, List list) {
        this.count = count;
        this.list = list;
    }

    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public List getList() {
        return list;
    }
    public void setList(List list) {
        this.list = list;
    }

}

最後,咱們建立一個類——UserDao.java。UserDao類裏面編寫代碼實現對數據庫完整的操做(CRUD)。

public class UserDao {

    /* * 保存 */
    public void save(User user) {
        Session session = HibernateUtils.openSession();
        try {
            Transaction tx = session.beginTransaction(); // 開啓事務
            session.save(user);
            tx.commit(); // 提交事務
        } catch (RuntimeException e) {
            session.getTransaction().rollback(); // 回滾事務
            throw e;
        } finally {
            session.close(); // 關閉session
        }
    }

    /* * 更新 */
    public void update(User user) {
        Session session = HibernateUtils.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();

            session.update(user);// 操做

            tx.commit();
        } catch (RuntimeException e) {
            tx.rollback();
            throw e;
        } finally {
            session.close();
        }
    }

    /* * 刪除 */
    public void delete(int id) {
        Session session = HibernateUtils.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();

            Object user = session.get(User.class, id); // 要先獲取到這個對象
            session.delete(user); // 刪除的是實體對象

            tx.commit();
        } catch (RuntimeException e) {
            tx.rollback();
            throw e;
        } finally {
            session.close();
        }
    }

    /* * 根據id查詢一個User數據 */
    public User getById(int id) {
        Session session = HibernateUtils.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            User user = (User) session.get(User.class, id);// 操做
            tx.commit();
            return user;
        } catch (RuntimeException e) {
            tx.rollback();
            throw e;
        } finally {
            session.close();
        }
    }

    /* * 查詢全部 */
    public List<User> findAll() {
        Session session = HibernateUtils.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();

            // 方式一:使用HQL語句
            List<User> list = session.createQuery("FROM User").list(); // 使用HQL查詢

            tx.commit();
            return list;
        } catch (RuntimeException e) {
            tx.rollback();
            throw e;
        } finally {
            session.close();
        }
    }

    /** * 分頁的查詢數據列表 * @param firstResult 從結果列表中的哪一個索引開始取數據 * @param maxResults 最多取多少條數據 * @return 一頁的數據列表 */
    @SuppressWarnings("unchecked")
    public QueryResult findAll(int firstResult, int maxResults) {
        Session session = HibernateUtils.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            // 查詢一頁的數據列表
            // 方式一:
            // Query query = session.createQuery("FROM User");
            // query.setFirstResult(firstResult);
            // query.setMaxResults(maxResults);
            // List<User> list = query.list(); // 使用HQL查詢

            // 方式二:方法鏈
            List<User> list = session.createQuery( //
                    "FROM User") //
                    .setFirstResult(firstResult) // 
                    .setMaxResults(maxResults) //
                    .list();

            // 查詢總記錄數
            // session.createQuery("SELECT COUNT(*) FROM User").list().get(0);
            // Long count = (Long) session.createQuery("SELECT COUNT(*) FROM User").uniqueResult();
            Long count = (Long) session.createQuery( //
                    "SELECT COUNT(*) FROM User") //
                    .uniqueResult();
            tx.commit();

            // 返回結果
            return new QueryResult(count.intValue(), list);
        } catch (RuntimeException e) {
            tx.rollback();
            throw e;
        } finally {
            session.close();
        }
    }

}

在以下兩個方法中:

  • public List<User> findAll()
  • public QueryResult findAll(int firstResult, int maxResults)

咱們使用到了Hibernate查詢語句——HQL(Hibernate Query Language),後面將會詳細講解,這裏稍微瞭解一下便可,咱們只要會用就好。

HQL(Hibernate Query Language)與SQL類似,查詢的是對象和對象中的屬性,關鍵字不區分大小寫,但類名與屬性名區分大小寫;而SQL查詢的是表和表中的字段,一樣也不區分大小寫。
接下來,爲方便測試,咱們使用單元測試來測試以上編寫的代碼。咱們只要右鍵點擊UserDao類→New→JUnit Test Case,以下:

這裏寫圖片描述

接下來會彈出以下對話框:

這裏寫圖片描述

這是要幫咱們自動建立UserDao測試類的節奏。
接着點擊Next按鈕,在彈出的對話框中選中咱們要測試的UserDao類中的方法。

這裏寫圖片描述

最後點擊Finish完成,這時Eclipse就幫咱們自動建立UserDao類的測試類
——UserDaoTest.java了,而後咱們再在其中編寫測試代碼。

public class UserDaoTest {

    private UserDao userDao = new UserDao();

    @Test
    public void testSave_1() {
        User user = new User();
        user.setName("張三");

        // 保存
        userDao.save(user);
    }

    @Test
    public void testGetById() {
        User user = userDao.getById(1);
        System.out.println(user);
    }

    @Test
    public void testUpdate() {
        // 從數據庫中獲取一條存在的數據
        User user = userDao.getById(1);
        user.setName("李四");
        // 更新
        userDao.update(user);
    }

    @Test
    public void testDelete() {
        userDao.delete(1);
    }

    // -------------------------

    @Test
    public void testSave_25() {
        for (int i = 1; i <= 25; i++) {
            User user = new User();
            user.setName("test_" + i);

            userDao.save(user); // 保存
        }
    }

    @Test
    public void testFindAll() {
        List<User> list = userDao.findAll();
        for (User user : list) {
            System.out.println(user);
        }
    }

    @Test
    public void testFindAllIntInt() {
        // 查詢
        // QueryResult qr = userDao.findAll(0, 10); // 第1頁,每頁10條
        // QueryResult qr = userDao.findAll(10, 10); // 第2頁,每頁10條
        QueryResult qr = userDao.findAll(20, 10); // 第3頁,每頁10條

        // 顯示結果
        System.out.println("總記錄數:" + qr.getCount());
        for (User user : (List<User>) qr.getList()) {
            System.out.println(user);
        }

    }

}

測試經過,Hibernate入門完結!