Hibernate第二天:Hibernate的一級快取、其他的API
Hibernate第二天:Hibernate的一級快取、其他的API
目錄
Hibernate第二天:Hibernate的一級快取、其他的API
1持久化類的編寫規則
1.1什麼是持久化類
持久化,將記憶體中的一個物件持久化到資料庫的過程。Hibernate框架就是用來進行持久化的框架。
持久化類,一個Java物件與資料庫表建立了對映關係,那麼這個類在Hibernate中稱為持久化類。
持久化類=Java類+對映檔案。
1.2持久化類的編寫規則
- 持久化類提供一個無參的構造方法 Hibernate底層需要使用反射生成例項。
- 屬性需要私有,對私有屬性提供public的set和get方法:Hibernate中獲取,設定物件的值。
- 對持久化類提供一個唯一的標識OID與資料庫主鍵對應:Java中通過物件的地址區是否是同一個物件,資料庫表中通過主鍵繫結是否是同一個記錄,在Hibernate中通過持久化類的OID的屬性區分是否是同一個物件。
- 持久化類中的屬性,儘量使用包裝類型別:因為基本資料型別預設值是0,會有很多歧義,包裝類預設值為NUll。
- 持久化類不要用使用final進行修飾:延遲載入本身是hibernate一個優化的手段,返回的是一個代理物件(javassist可以對沒有實現介面的類產生代理-使用了非常底層的位元組碼增強技術,繼承這個類進行代理),如果不能繼承,不能產生代理物件,延遲載入就會失效,load()和get()方法一致。
2主鍵生成策略
2.1主鍵的分類
2.1.1自然主鍵
- 自然主鍵,主鍵的本身就是表中的一個欄位(實體中的一個具體屬性)。
- 建立一個人員表,人員就會有一個身份證號(唯一且不可重複),使用了身份證號作為主鍵,這種主鍵稱為是自然主鍵。
2.1.2代理主鍵
- 代理主鍵,主鍵的本身不是表中必須的一個欄位(不是實體中的某個具體屬性)。
- 建立一個人員表,沒有使用人員中的身份證號,用了一個與這個表不相關的欄位ID,(PNO)。這種主鍵稱為是代理主鍵。
在實際開發中,儘量使用代理主鍵,因為一旦主鍵參與到業務邏輯中,後期可能需要修改原始碼。好的程式設計滿足OCP原則,對程式的擴充套件是Open的,對修改原始碼是close的。
2.2主鍵生成策略
在實際開發中,一般不允許使用者手動設定主鍵,一般將主鍵交給資料庫,或者手動編寫程式進行設定。在Hibernate中為了減少程式編寫,提供了很多主鍵生成策略。
- Increment :hibernate中提供的自動增長機制,適用short,int,long型別黨的主鍵,在單執行緒中使用。首先發送一條語句,select id from 表,然後讓id+1作為下一條記錄的主鍵。
- Identity:自動增長,適用short,int,long型別的主鍵,使用的是資料庫底層的自動增長,適用於有自動增長機制的資料庫(MySQL,MSSQL),Oracle沒有自動增長。
- Sequence:自動增長,適用short,int,long型別的主鍵,採用序列方式(Oracle支援序列)。Mysql不能使用。
- UUID:適用於字串型別,使用Hibernate中的隨機方式生成字串主鍵。
- Native:本地策略,可以在Identity和Sequence之間進行自動切換。
- Assigned:hibernate放棄外來鍵管理,需要通過手動編寫程式或者自己設定。
- Foreign:外部的,一對一的關聯對映的情況下使用。(瞭解)
3持久化類的三種狀態
3.1持久化類的三種狀態
Hibernate是持久層框架,通過持久化類完成ORM操作,為了更好的管理持久化類,hIbernate把持久化類分層三種轉態。
持久化類=Java類+對映
(1)瞬時態(Transient):沒有唯一標識OID,沒有被Session管理。
(2)持久態(Persistent):有唯一標識OID,被Session管理。
(持久化類的持久態物件,可以自動更新資料庫)
(3)脫管態(Detached):有唯一標識OID,沒有被Session管理。
3.2區分三種狀態物件
@Test
// 三種狀態區分
public void demo1() {
// 1通過工具類獲取Session
Session session = HibernateUtils.openSession();
// 2開啟事務
Transaction tx = session.beginTransaction();
// 3操作
// 向資料庫插入一條記錄
Customer Customer = new Customer(); // 1.瞬時態:沒有位移標識OID(主鍵id),沒有被session管理
Customer.setCust_name("小涵涵"); //
session.save(Customer); // 2.持久太:有唯一標識OID,被session管理
// 4事務提交 //
tx.commit(); //
// 5釋放資源 //
session.close(); //
System.out.println(Customer.getCust_name()); // 3.託管態:有唯一標識OID,沒有被session管理
}
3.3持久化類的狀態轉換(瞭解)
- 瞬時態:
獲得:由new關鍵字建立
- 瞬時態轉換為持久態:執行Session中的save()方法或saveOrUpdate0方法
- 瞬時態轉換為脫管態:為瞬時態物件設定持久化標識OID
Customer customer = new Customer)://瞬時態customersetCust id(1); //脫管態
(2)持久態,
獲得,通過Session的get()、load()方法或者Quey查詢從資料庫中獲得.
- 持久態轉換為瞬時態:執行Session中的delete()方法。
- 持久態轉換為脫管態:執行Session的evict()、close()或clear()方法用於清除一級快取中某個物件,clear()清除一級快取 中的所有物件。
(3)脫管態,
獲得,脫管態無法獲得,只能由其他狀態轉換而來。
- 脫管態轉換為持久態, 執行Session的update()、 saveOrUpdate()或lock()方法。
- 脫管態轉換為瞬時態,將脫管態物件的持久化標識OID設定為null
3.4持久化類持久態物件自動更新資料庫
@Test
/****
* 持久太的物件可以以自動更新資料庫
*/
public void demo2() {
// 1通過工具類獲取Session
Session session = HibernateUtils.openSession();
// 2開啟事務
Transaction tx = session.beginTransaction();
// 3操作
/** 獲取一個持久太物件了 **/
Customer Customer = (Customer) session.get(Customer.class, 1l);
Customer.setCust_name("王哈哈");
/** 此處可以省略一個update(如果此處資料和資料庫一樣,不執行Update()) **/
//session.update(Customer);
// 4事務提交
tx.commit();
// 5釋放資源
session.close();
}
4Hibernate的一級快取
4.1快取概述
快取是一種優化的方式,將一些資料放在記憶體,使用的時候直接從快取中獲取,不用通過資料來源。
4.2Hibernate快取
4.2.1Hibernate一級快取
Hibernate一級快取又稱為“Session的快取”。
Session內建不能被解除安裝,Session的快取是事務範圍的快取(Session物件的生命週期通常對應一個數據庫事務或者一個應用事務)。
一級快取中,持久化類的每個例項都具有唯一的OID。
依賴於hibernate一級快取【就是將資料庫/硬碟檔案中資料,放到快取中(就是記憶體中一塊空間),當再次使用時,可以直接從記憶體中獲取資料資訊】。
4.2.2證明Hibernate一級快取存在
@Test
/****
* 證明一級快取的存在
*/
public void demo3() {
// 1通過工具類獲取Session
Session session = HibernateUtils.openSession();
// 2開啟事務
Transaction tx = session.beginTransaction();
// 3操作
/**
* 分別用兩次get執行兩次查詢id=1的客戶,按道理執行兩次get應傳送兩條sql語句,
* 且Customer1與Customer2不是同一個物件,
* 實際上只發送一次,且Customer1與Customer2是同一個物件
* 證明第二次查詢使用的是一級快取中的資料
**/
/** 資料庫中第一本書的資訊 **/
Customer Customer1 = (Customer) session.get(Customer.class, 1l);
System.out.println(Customer1);
/** 一級快取中中第一本書的資訊 **/
Customer Customer2 = (Customer) session.get(Customer.class, 1l);
System.out.println(Customer2);
System.out.println(Customer1==Customer2);
// 4事務提交
tx.commit();
// 5釋放資源
session.close();
}
4.2.3Hibernate一級快取結構
@Test
/****
* 深入瞭解持久態的物件可以以自動更新資料庫
* 基於一級快取:快照區
*/
public void demo4() {
// 1通過工具類獲取Session
Session session = HibernateUtils.openSession();
// 2開啟事務
Transaction tx = session.beginTransaction();
// 3操作
Customer Customer = (Customer) session.get(Customer.class, 1l);
/** 將資訊儲存於快照區 **/
Customer.setCust_name("張三丰");// 先將一級快取區的【cust_name】修改為【"張三丰"】-----中間會進行一個比對檢視是否一致,如果一致不更新(不會執行update語句),如果不一致----再將快照區中的【cust_name】修改為【"張三丰"】(執行update語句)。
// 4事務提交
tx.commit();
// 5釋放資源
session.close();
}
5Hibernate的事務管理
5.1什麼是事務
事務:指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。
5.2事務的特性
1.原子性
(Atomic)(Atomicity)
事務必須是原子工作單元;對於其資料修改,要麼全都執行,要麼全都不執行。
2.一致性
(Consistent)(Consistency)
事務在完成時,必須使所有的資料都保持一致狀態。
3.隔離性
(Insulation)(Isolation)
由併發事務所作的修改必須與任何其它併發事務所作的修改隔離。
4.永續性
(Duration)(Durability)
事務完成之後,它對於系統的影響是永久性的。該修改即使出現致命的系統故障也將一直保持。
5.3如果不考慮隔離性,引發安全性問題
讀的問題:
髒讀:一個事務讀到另一個事務未提交的資料。
不可重複讀:一個事務讀到另一個事務已經提交的update資料,導致在前一個事務多次查詢結果不一致。
虛讀:一個事務讀到另一個事務已經提交的insert資料,導致在前一個事務多次查詢結果不一致。
寫問題(瞭解)
引發丟失更新。
5.3讀問題的解決
設定事務的隔離級別
① Serializable (序列化):可避免髒讀、不可重複讀、幻讀的發生。
② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
③ Read committed (讀已提交):可避免髒讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
在MySQL資料庫中,支援上面四種隔離級別,預設的為Repeatable read (可重複讀);而在Oracle資料庫中,只支援Serializable (序列化)級別和Read committed (讀已提交)這兩種級別,其中預設的為Read committed級別。
5.4Hibernate設定事務隔離級別
核心配置檔案中加入:
<!-- 事務隔離級別
0:TRANSACTION_NONE
1:TRANSACTION_READ_UNCOMMITTED
2:TRANSACTION_READ_COMMITTED
4:TRANSACTION_REPEATABLE_READ
8:TRANSACTION_SERIALIZABLE
-->
<property name="hibernate.connection.isolation">4</property>
5.5Hibernate解決Service的事務管理
改寫工具類:
package top.yangxianyang.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Hibernate的工具類
* @author yxy
*
*/
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sf;
static{
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
/*
* 提供獲得session的方法
*/
public static Session openSession(){
return sf.openSession();
}
/*
* 提供獲得session的方法
*/
public static Session getCurrentSession(){
return sf.getCurrentSession();
}
}
核心檔案配置:
<!-- 配置當前執行緒繫結的Session -->
<property name="hibernate.current_session_context_class">thread</property>
程式碼:
package top.yangxianyang.demo1;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import top.yangxianyang.utils.HibernateUtils;
/*
* Hibernate執行緒繫結Session
* @author yxy
*
*/
public class HibernateTest3 {
@Test
public void demo1(){
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
Customer Customer = new Customer();
Customer.setCust_name("涵涵");
session.save(Customer);
tx.commit();
}
}
6Hibernate的其他API
6.1Query
1 使用query物件,不需要寫sql語句,但是寫hql語句
(1)hql:hibernate query language,hibernate提供查詢語言,這個hql語句和普通sql語句很相似
(2)hql和sql語句區別:
- 使用sql操作表和表字段
- 使用hql操作實體類和屬性
2 查詢所有hql語句:
(1)from 實體類名稱
3 Query物件使用
(1)建立Query物件
(2)呼叫query物件裡面的方法得到結果
@Test
//Query
public void demo1(){
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
//通過session獲得Query介面
//String hql="from Customer";//簡單查詢
//條件查詢
//String hql="from Customer where cust_name like ?";
//分頁查詢
String hql="from Customer";
Query query=session.createQuery(hql);
//設定條件
//query.setParameter(0, "張%");
//設定分頁
query.setFirstResult(0);
query.setMaxResults(2);
List<Customer> list=query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
6.2Criteria
1使用這個物件時候,不需要寫語句,直接呼叫方法實現,更加面向物件。
2 實現過程
(1)建立criteria物件
(2)呼叫物件裡面的方法得到結果
@Test
//Criteria
public void demo2(){
Session session=HibernateUtils.getCurrentSession();
Transaction tx=session.beginTransaction();
//通過session獲得Criteria物件
Criteria ct=session.createCriteria(Customer.class);
//條件查詢
ct.add(Restrictions.like("cust_name", "張%"));
List<Customer> list=ct.list();
//分頁
ct.setFirstResult(0);
ct.setMaxResults(2);
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
6.3SQLQuery
1 使用hibernate時候,呼叫底層sql實現
2 實現過程
(1)建立物件
(2)呼叫物件的方法得到結果
@Test
// 查詢所有
public void demo6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 接收SQL:
SQLQuery query = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tx.commit();
session.close();
}
今天任務完成。
原始碼地址:
連結:https://pan.baidu.com/s/1rMQ9XBMIeu2O_VbNZBo3MQ 密碼:0hgz