Hibernate框架簡介②

Milky-way發表於2018-08-10

模型類的規範:

1 必須有預設構造方法, 查詢時把資料表中的一條資料對映成一個物件時需要使用預設構造器來建立物件

2 必須提供一個OID, 作為物件的主鍵(就是userId了)

3 屬性必須私有化封裝, 就是提供set跟get方法

4 不要使用final來修飾模型類中的成員, 如果是final修飾在後續要講到的延遲載入無法實現

5 最好使用封裝類,

    基本型別 int  預設值是0

    包裝類    Integer  預設值是null

    假如該值本來沒有填寫, 由於是基本型別, 系統將預設值0代替它而不是null, 因而你無法判斷是填寫了0還是預設值

 

對映檔案詳解:

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

<!-- 
    package: 指定當前對映檔案的實體類的包路徑
 -->
<hibernate-mapping package="com.rl.hiber.model">

    <!-- 
        class: 實體類名
        table: 對應資料庫表名
     -->
    <class name="User" table="t_user">
    <!--
                設定主鍵 
        generator: 主鍵的生成策略(後續再介紹)
     -->
        <id name="userId" column="user_id">
        <!-- 
            identity(常用): 使用mysql的自增策略, 這種自增沒有併發問題, 前提是model的oid是數值型別, 所對映的column也是數值型別
            native(比較智慧): 根據資料庫的方言來翻譯, 自動翻譯成identity(mysql)或sequence(oracle)
            uuid(有大量使用, 由於沒有鎖機制, 效能較高): 沒有併發問題, 按照自己的策略生成一個32位的字串, 主鍵不重複, 前提是主鍵(oid)必須是字串型別
            assigned: 手動指定id(在實際專案中不使用)
            increment: 主鍵自動自增(在實際專案中不去使用, 因為有併發安全性問題)
         -->
            <generator class="identity"></generator>
        </id>
        <!-- 
            name: 實體類的屬性名
            column: 資料庫表中的列名
            可選屬性:
            type: 設定欄位型別(一般不用設定)
            length: 設定欄位長度
            not-null: 設定非空約束
            unique-key: 設定唯一鍵約束
         -->
        <property name="uname" column="uname"></property>
        <property name="gender" column="gender"></property>
        <property name="birthday" column="birthday"></property>
    </class>
</hibernate-mapping>

環境初始化詳解:

Configuration: 建立Hibernate配置物件, 讀取hibernate.cfg.xml檔案初始化環境

ServiceRegistry: 註冊hibernate屬性資訊

SessionFactory: Session工廠類, 這個類是一個重量級的物件, 執行緒安全的, 負責建立Session, 這個物件在伺服器啟動的時候建立一個即可

Session: 是一次和資料庫的會話, 但是不一定是一次連線, Session給我們提供了很多運算元據庫的方法, 操作的是物件, 影響的是資料庫

Transaction: 事務物件, 控制我們Session物件資料庫操作的事務

 

封裝一個工具類以簡化程式碼:

HibernateUtil類:

package com.rl.hiber.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

    private static SessionFactory sf;
    
    //靜態塊
    static {
        
        Configuration cfg = new Configuration();
        cfg.configure("hibernate.cfg.xml");
        ServiceRegistry sr = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
        sf = cfg.buildSessionFactory(sr);
    }
    
    public static SessionFactory getSessionFactory() {
        return sf;
    }
    
    public static Session getSessoion() {
        return sf.openSession();
    }
    
    public static void closeSession(Session session) {
        session.close();
    }
    
    public static void closeResource(Session session) {
        session.close();
        sf.close();
    }
}

修改測試程式碼:

package com.rl.hiber.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;

public class TestHibernate {

    
    
    @Test
    public void test2() {
        
        //獲取session
        Session session = HibernateUtil.getSessoion();
        //需要先開啟事務
        Transaction tx = session.beginTransaction();
        try {
            //建立物件
            User user = new User();
            user.setUname("zhangsan");
            user.setGender(1);
            user.setBirthday(new Date());
            //儲存user物件到資料庫中
            session.save(user);
            //事務提交
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            HibernateUtil.closeResource(session);
        }
    }
}

資料庫結果與之前一致:

hibernate的物件的三種狀態

瞬時物件(TransientObjects): 

    剛new出來的物件, 在資料庫中沒有相應的記錄, 也沒有被session管理起來的物件

持久化物件(PersistentObjects): 

    在資料庫中有相應的記錄並且被session管理來的物件

脫管物件(DetachObjects):

    在資料庫中有相應的記錄, 但沒有被session管理起來的物件

這三種狀態可以相互轉換

    當瞬時物件執行save()或者update()時會轉換為持久化物件

    當執行get()或load()或iterator()時從資料庫中查詢上來的物件就是持久化物件, 當持久化物件執行delete()時則轉換為瞬時物件

    當持久化物件執行evict()或close()或clear()時則轉換為脫管物件

    當脫管物件執行save()或update()時則轉換為持久化物件

    當脫管物件執行delete()時則轉換為瞬時物件

 

由於其中的某些轉換較為簡單, 我只貼出一些我認為需要記憶的點

脫管物件轉換為持久化物件, 一旦成為脫管物件了, 那麼久意味著該物件只存在於資料庫中, 此時session已經關閉了, 要想重新轉換為持久化物件, 則必須新建立出一個session, 請看測試程式碼:

package com.rl.hiber.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;

public class TestHibernate {

    
    @Test
    public void test3() {
        Session session = HibernateUtil.getSessoion();
        Transaction tx = session.beginTransaction();
        User user = new User();
        try {
            user.setUname("張三");
            user.setBirthday(new Date());
            user.setGender(1);
            session.save(user);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            //關閉session, 此時將物件user變成脫管物件
            HibernateUtil.closeSession(session);
        }
        
        //重新建立一個session
        Session session2 = HibernateUtil.getSessoion();
        Transaction tx2 = session2.beginTransaction();
        try {
            user.setUname("李四");
            session2.update(user);
            tx2.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx2.rollback();
        }finally {
            //關閉session2
            HibernateUtil.closeResource(session2);
        }
    }
}

此時就將user物件轉成了持久化物件(既被session管理, 又存在於資料庫中)

 

通過查詢獲得持久化物件, 請看測試程式碼:

package com.rl.hiber.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;

public class TestHibernate {

   
    
    @Test
    public void test2() {
        
        Session session = HibernateUtil.getSessoion();
        try {
            User user = (User) session.get(User.class, 1);
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            HibernateUtil.closeResource(session);
        }
    }
    
    
}

tip: 查詢並不需要開事務

 

這裡先貼上load()的查詢, 後續會講解它們的區別(與延遲載入有關)

測試程式碼:

package com.rl.hiber.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;

public class TestHibernate {

    
    
    @Test
    public void test4() {
        Session session = HibernateUtil.getSessoion();
        try {
            User user = (User) session.load(User.class, 1);
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            HibernateUtil.closeResource(session);
        }
    }
    
   
}

get()和load()方法查詢出來的物件都是持久化物件

 

相關文章