hibernate快速入門示例

王希知發表於2020-07-01

hibernate概述

hibernate是一個java的全自動ORM框架,它可以自動生成SQL語句、自動建表、自動執行,使用者可以不使用SQL完成資料的CRUD操作,同時它也是基於JPA規則的一種實現方式

建庫建表

在mysql資料庫中建立測試庫和表

-- 建庫
CREATE DATABASE `hibernate-test`;

-- 建表
CREATE TABLE `hibernate-test`.`h_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- 插入資料
INSERT INTO h_user ( username, PASSWORD )
VALUES
	( 'zhangsan', '123' );
INSERT INTO h_user ( username, PASSWORD )
VALUES
	( 'lisi', '321' );

建立專案

本例項全程使用idea進行,並使用maven匯入依賴jar包

匯入依賴

在maven的pom檔案中加入hibernate的核心依賴包,為了方便使用模型,這裡我還匯入了lombok包,用於簡寫getter、setter等實體類方法

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.4.18.Final</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.48</version>
    </dependency>
</dependencies>

編寫對映資料庫的物件模型實體

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}

建立hibernate配置檔案

核心配置檔案

hibernate核心配置檔案預設命名為hibernate.cfg.xml, 檔案的預設路徑是在類目錄下,這裡我放在resources資料夾下

.cfg : configuration

<?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>
        <!-- 資料庫連線基本配置資訊 必填-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate-test?serverTimezone=GMT%2B8</property>
        <!-- 資料庫方言:指定使用的資料庫種類 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!-- 是否顯示sql程式碼,用於在控制檯輸出執行的SQL語句 可選-->
        <property name="hibernate.show_sql">true</property>
<!--        格式化SQL,美化SQL語句輸出 可選-->
        <property name="hibernate.format_sql">true</property>
<!--        自動生成表策略
            update: 若存在表則不生成表
            create: 不管存在不存在都重新建立
-->
        <property name="hibernate.hbm2ddl.auto">update</property>
<!--        指定對映配置檔案的位置-->
        <mapping resource="com/welisit/hibernate/demo/model/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>

物件關係對映配置檔案

對映配置檔案預設命名使用[實體類名].hbm.xml,檔案的預設路徑放在與實體類的同個目錄下,這裡我的對映配置檔名為User.hbm.xml

.hbm: hibernate mapper

<?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>
<!--   name: 實體類的全類名
       table: 表名
-->
    <class name="com.welisit.hibernate.demo.model.User" table="h_user">
        <id name="id" column="id">
<!--            主鍵生成方式
        native:使用資料庫設定的主鍵生成方式
-->
            <generator class="native"/>
        </id>
        <property name="username" column="username"/>
        <property name="password" column="password"/>
    </class>
</hibernate-mapping>

測試

增加記錄

public void testInsert() {
        // 建立hibernate核心配置檔案物件
        Configuration configuration = new Configuration();
        Configuration configure = configuration.configure();
        // 建立能夠構建session的sessionfactory
        SessionFactory sessionFactory = configure.buildSessionFactory();
        // 一個session相當於一個連線, 通過session物件開啟事務
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        // 建立對映物件模型
        User user = new User();
        user.setPassword("312");
        user.setUsername("aaa");
        // 儲存物件
        session.save(user);
        // 提交事務
        transaction.commit();
        // 關閉會話
        session.close();
        // 關閉session工廠
        sessionFactory.close();
    }

執行上面的程式碼我們發現有報錯,內容大概是mapping對映檔案找不到

image-20200628203555298

// 報錯資訊
org.hibernate.boot.MappingNotFoundException: Mapping (RESOURCE) not found : com/welisit/hibernate/demo/model/User.hbm.xml : origin(
    ...

通過檢視編譯輸出檔案發現原來在java資料夾中的沒有User.hbm.xml,因為maven專案中,預設java目錄中除了生成編譯後的.class檔案是不會生成其他型別的檔案的。

image-20200628205141720

解決方法:

方式一:直接將User.hbm.xml檔案複製到輸出檔案目錄中即可

方式二:修改maven的pom檔案中的編譯打包配置

<!-- 專案打包時會將java目錄中的*.xml檔案也進行打包 -->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

通過檢視configure方法原始碼,可以看出預設hibernate核心配置檔名就是hibernate.cfg.xml

image-20200628195125305

刪除、修改

修改和刪除需要開啟事務才能進行

public void testUpdate() {
    Session session = sessionFactory.openSession();
    // 獲取修改的物件
    User user = session.get(User.class, 1);
    // 修改物件值
    user.setUsername("abc");
    // 更新需要開啟事務
    Transaction transaction = session.beginTransaction();
    session.update(user);
    transaction.commit();
}

public void testRemove() {
    Session session = sessionFactory.openSession();
    // 獲取修改的物件
    User user = session.get(User.class, 1);
    Transaction transaction = session.beginTransaction();
    // 刪除物件值
    session.remove(user);
    transaction.commit();
}

查詢

通過主鍵查詢

hibernate原生的session物件提供了通過物件主鍵查詢的方法

  • get(javaBean.class, int id); 通過傳入的id進行查詢
  • load(javaBean.class, int id); 同上,但這是懶載入
@Test
public void queryById() {
    Session session = sessionFactory.openSession();
    User user = session.load(User.class, 2);
    System.out.println("懶載入執行完畢...");
    System.out.println(user);
}

輸出結果

image-20200630134529067

HQL查詢

簡介

HQL是Hibernate Query Language的縮寫,提供更加豐富靈活、更為強大的查詢能力;HQL更接近SQL語句查詢語法,它是對查詢條件進行了物件導向封裝。

示例

@Test
public void testHQL() {
    // 使用hql語句查詢
    Session session = sessionFactory.openSession();
    // User類名在對映配置檔案的hibernate-mapping標籤配置了報名就可以在此不加包名 
    // ?1 指定佔位符的索引數為1
    String hql = "from User where username = ?1";
    // 引數也可以使用指定名稱
    // String hql2 = "from User where username = :name"
    Query<User> query = session.createQuery(hql, User.class);
    query.setParameter(1, "aaa");
    // query.setParameter("name", "aaa");
    // 獲取單個返回結果值
    User user = query.getSingleResult();
    System.out.println(user);
}

@Test
public void testHQL2() {
    // 使用hql語句查詢
    Session session = sessionFactory.openSession();
    // User類名在對映配置檔案的hibernate-mapping標籤配置了報名就可以在此不加包名
    // ?1 指定佔位符的索引數為1
    String hql1 = "from User where username = ?1";
    Query<User> query = session.createQuery(hql1, User.class);
    query.setParameter(1, "aaa");
    // 查詢結果為多個值時使用getSingleResult會怎樣? 會報錯:
    // javax.persistence.NonUniqueResultException: query did not return a unique result: 2
    // getSingleResult實際呼叫的就是this.uniqueResult()
    User user = query.getSingleResult();
    System.out.println(user);
}

分頁查詢示例

@Test
public void testHQLPage() {
    // 使用hql語句分頁查詢
    Session session = sessionFactory.openSession();
    String hql = "from User";
    Query<User> query = session.createQuery(hql, User.class);
    query.setFirstResult(0); // 從第幾條開始查詢
    query.setMaxResults(2); // 每次查詢顯示幾條
    List<User> userList = query.list();
    userList.forEach(System.out::println);
}

輸出結果:

image-20200630142714388

SQL查詢

hibernate也支援原生SQL來進行查詢

示例

@Test
public void testSQLQuery() {
    // 原生SQL查詢
    Session session = sessionFactory.openSession();
    String sql = "select * from h_user";
    // 建立sql查詢物件
    NativeQuery sqlQuery = session.createSQLQuery(sql);
    // 指定結果集封裝到哪個物件
    sqlQuery.addEntity(User.class);
    List list = sqlQuery.list();
    list.forEach(System.out::println);
}

QBC查詢

曾經我一直幻想著什麼時候可以不使用SQL就能對資料庫進行增刪改查操作,這樣就能少學一點東西了。現在QBC出現了,就是和我幻想的一樣,不需要寫一條語句就能對資料庫完成各種CRUD操作,方便省事、節省寫sql時間,讓更多時間用在業務的邏輯開發中而不是這種簡單的CRUD程式碼中。

QBC: query by Criteria 【Criteria】條件、標準

使用步驟

QBC查詢是通過建立查詢物件對資料物件進行操作,首先第一步就是建立查詢物件

Criteria criteria = session.createCriteria(User.class)

使用Restrictions構建條件,通過查詢物件設定查詢條件,最後得出結果

@Test
public void testQBCQuery() {
    // QBC查詢
    Session session = sessionFactory.openSession();
    Criteria criteria = session.createCriteria(User.class);
    criteria.add(Restrictions.eq("username", "aaa"));
    Object o = criteria.uniqueResult();
    System.out.println(o);
}

聚合查詢

@Test
public void testQBCQuery2() {
    // QBC聚合查詢
    Session session = sessionFactory.openSession();
    Criteria criteria = session.createCriteria(User.class);
    criteria.setProjection(Projections.count("id"));
    Object o = criteria.uniqueResult();
    System.out.println(o);
}

hibernate對映檔案詳解

hibernate-mapping

<!-- 配置表和實體類的對映關係 -->
<hibernate-mapping package="對映類所在的包">

package屬性: 指定實體類所在的包,凡是需要填寫包名的地方,使用這個之後,都可以省略,只寫類名

class

配置資料庫表與類的對應的關係

<class name="com.welisit.hibernate.demo.model.User" table="h_user">
  • name: 完整類名
  • table: 資料庫表名

class 標籤內部包含兩部分:idproperty

id

配置主鍵對映的屬性

  • name:填寫主鍵對應屬性名

  • column:填寫表中主鍵列名

  • type(可選):填寫列(屬性)的型別.hibernate會自動檢測實體的屬性型別.

​ 每個型別有三種填法: java型別|hibernate型別|資料庫型別

  • not-null(可選):配置該屬性(列)是否不能為空. 預設值:false

  • length(可選):配置資料庫中列的長度. 預設值:使用資料庫型別的最大長度

id標籤內部包含 generator標籤

generator

元件生成策略

<generator class="native"/>

class屬性的幾個可選值

  • identity: 由資料庫來維護,hiibernate不負責

  • increment: 每次插入前,先獲取資料表中最大值,然後+1

  • sequence: 用資料庫提供的sequence機制生成主鍵,需要資料庫支援sequence,mysql不支援

  • hilo: 通過高低位演算法實現

    hilo(高低位方式high low)是hibernate中最常用的一種生成方式,需要一張額外的表儲存hi的值。儲存hi值的表至少有一條記錄(只與第一條記錄有關),否則會出現錯誤。可以跨資料庫。

  • native: 使用資料庫原生設定的生成策略

  • UUID:使用uuid演算法生成的id,但是需要注意主鍵必須是String

  • assigned: 由程式設計師自己決定,在儲存時指定id進行儲存

property

除id之外的普通屬性對映

屬性配置引數與id標籤相同

總結

hibernate雖然現在新專案用得不多,但是不可否則它曾經在ORM框架中的地位,同時它也是學習spring data jpa的基礎,hibernate仍是一個優秀的ORM框架