【Hibernate(二)】持久化類、主鍵生成策略和一級快取
1.2 持久化類的編寫規則
1.2.1 持久化類的概述
什麼是持久化類
持久化:將記憶體中的一個物件持久化到資料庫中過程。Hibernate框架就是用來進行持久化的框架。
持久化類:一個Java物件與資料庫的表建立了對映關係,那麼這個類在Hibernate中稱為是持久化類。
持久化類 = Java類 + 對映檔案
1.2.2 持久化類的編寫規則
持久化類的編寫規則
對持久化類提供一個無參的構造方法:Hibernate底層需要使用反射生成例項。
屬性需要私有,對私有屬性提供public的get和set方法:Hibernate中獲取、設定物件的值。
對持久化類提供一個唯一標識OID與資料庫的主鍵相對應:Java中通過物件的地址區分是否是同一個物件,資料庫中通過主鍵確定是否是同一個記錄,在Hibernate中通過持久化類的OID的屬性區分是否是同一個物件。
持久化類中屬性儘量使用包裝類的型別:因為基本型別預設值是0,那麼0就會有很多的歧義。包裝型別預設值是null。
持久化類不要使用final進行修飾:延遲載入本身是hibernate一個優化的手段,返回的是一個代理物件(javassist可以對沒有實現介面的類產生代理——使用了非常底層位元組碼增強技術,繼承這個類進行代理)。如果不能被繼承,不能產生代理物件,延遲載入也就失效。load方法和get方法一致。
1.3 主鍵生成策略
1.3.1 主鍵的分類
自然主鍵
自然主鍵:主鍵的本身就是表中的一個欄位(實體中的一個具體的屬性)。
建立一個人員表:人員都會有一個身份證號(唯一的不可重複的),使用了身份證號作為主鍵,這種主鍵稱為是自然主鍵。
代理主鍵
代理主鍵:主鍵的本身不是表中必須的一個欄位(不是實體中的某個具體的屬性)。
建立一個人員表:沒有使用人員中的身份證號,用了一個與這個表不相關的欄位ID、(PNO),這種主鍵稱為是代理主鍵。
在實際的開發當中,儘量使用代理主鍵。
一旦自然主鍵參與到業務邏輯當中,後期有可能需要修改原始碼。
好的程式設計滿足OCP原則,對程式的擴充套件是open的,對修改原始碼是close的。
1.3.2 主鍵的生成策略
Hibernate的主鍵生成策略
在實際的開發中一般不允許使用者手動設定主鍵,一般將主鍵交給資料庫,手動編寫程式進行設定。在hibernate中為了減少程式編寫,提供了很多中的主鍵的生成策略。
increment:hibernate中提供的自動增長機制,適用short、int、long型別的主鍵。在單執行緒程式中使用。
首先先發送一條語句:select max(id) from 表;然後讓id+1 作為下一條記錄的主鍵。
identity:適用於short、int、long型別的主鍵,使用的是資料庫底層的自動增長機制。適用於有自動增長機制的資料庫(MySQL、MSSQL),但是Oracle是沒有自動增長。
sequence:適用於short、int、long型別的主鍵,採用的是序列的方式。(Oracle支援序列)。像MYSQL就不能使用sequence。
uuid:適用於字串型別的主鍵。使用hibernate中的隨機方式生成字串主鍵。
native:本地策略,可以在identity和sequence之間進行自動切換。
assigned:hibernate放棄外來鍵的管理,需要通過手動編寫程式或者使用者自己設定。
foreign:外部的。一對一的一種關聯對映的情況下使用。(瞭解)
1.4 持久化類的三種狀態
1.4.1 持久化類的三種狀態
Hibernate是持久層框架,通過持久化類完成ORM操作,Hibernate為了更好的管理持久化類,將持久化類分成三種狀態。
持久化類 = Java類 + 對映
瞬時態(transient)
這種物件沒有唯一的標識OID,沒有被session管理,稱為是瞬時態物件。
持久態(persistent)
這種物件有唯一標識OID,被session管理,稱為是持久態物件。
脫管態(detached)
這種物件有唯一標識OID,沒有被session管理,稱為脫管態物件。
區分三種狀態物件
public class HibernateDemo2 {
@Test
//三種狀態的區分
public void demo1(){
Session = session = HibernateUtils.openSession;
Transaction = transaction = session.beginTransaction();
Customer customer = new Customer();//瞬時態物件:沒有唯一標識OID,沒有session管理
customer.setCust_name("王東");
Serializable id = session.save(customer);//持久態物件:有唯一標識OID,被session管理
transaction.commit();
session.close();
System.out.println("客戶名稱:"+ customer.getCust_name());//脫管物件:有唯一標識OID,沒有被session管理
}
}
1.4.2 持久化類的狀態轉換
三種狀態的轉換圖
瞬時態物件
獲得
Customer customer = new Customer();
狀態轉換
瞬時==》持久
save()、saveOrUpdate(Object obj);
瞬時==》託管
customer.setCust_id(1l);
持久態物件
獲得
get()、load()、find()、iterate()
Customer customer = session.get(Customer.class,1l);
狀態的轉換
持久==》瞬時
delete()
持久==》脫管
close()、clear()、evict(Object obj);
脫管態的物件
獲得
Customer customer = new Customer();
customer.setCust_id(1l);
狀態的轉換
脫管==》持久
update()、saveOrUpdate()
脫管==》瞬時
customer.setCust_id(null);
1.4.3 持久態物件特性
持久化類持久態物件自動更新資料庫
@Test
//持久態物件自動更新資料庫
public void demo2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//獲得持久態物件
Customer customer = session.get(Customer.class,1l);
customer.setCust_name("王西");
//session.update(customer);
transaction.commit();
session.close();
}
1.5 Hibernate的一級快取
1.5.1 快取的概述
什麼是快取
快取:是一種優化的方式,將資料存入到記憶體中,使用的時候直接從快取中獲取,不用通過儲存源。
1.5.2 Hibernate的快取
HIbernate的一級快取
HIbernate框架中提供了優化手段,快取、抓取策略。Hibernate中提供了兩種快取機制:一級快取、二級快取。
Hibernate的一級快取:稱為是session級別的快取,一級快取生命週期與session一致(一級快取是由session中的一系列的Java集合構成)。一級快取是自帶的不可解除安裝的。(Hibernate的二級快取是SessionFactory級別的快取,需要配置的快取)。
證明一級快取存在
public class HibernateDemo3 {
@Test
//證明一級快取的存在
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer1 = session.get(Customer.class,1l);//傳送SQL語句
System.out.println(customer1);
Customer customer2 = session.get(Customer.class,1l);//不傳送SQL語句
System.out.println(customer2);
System.out.println(customer1 == customer2);
tx.commit();
session.close();
}
}
1.5.3 Hibernate的一級快取的結構
一級快取中的特殊區域:快照區
@Test
//一級快取的快照區
public void demo2(){
Session session = new HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = session.get(Customer.class,1l);//傳送SQL語句查詢,同時放入到快取中
customer.setCust_name("王鳳");
tx.commit();
session.close();
}
一級快取的清空
@Test
//一級快取的快照區
public void demo3(){
Session session = new HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer1 = session.get(Customer.class,1l);//傳送SQL語句查詢,同時放入到快取中
session.clear();//清空所有
//session.evict(customer1);
Customer customer2 = session.get(Customer.class,1l);//傳送SQL語句查詢,同時放入到快取中
System.out.println(customer1);
System.out.println(customer2);
tx.commit();
session.close();
}
1.6 HIbernate的事務管理
1.6.1 事務的回顧
什麼是事務
事務:事務指的是邏輯上的一組操作,組成這組操作的各個邏輯單元要麼全部成功,要麼全部失敗。
事務特性
原子性:代表事務不可分割。
一致性:代表事務執行的前後,資料的完整性保持一致。
隔離性:代表一事務執行的過程中,不應該受到其他事物的干擾。
永續性:代表事務執行完成後,資料就持久到資料庫中。
如果不考慮隔離性,引發安全性問題
讀問題
髒讀:一個事務讀到另一個事務未提交的資料。
不可重複讀:一個事務讀到另一個事物已經提交的update資料,導致在前一個事務多次查詢結果不一致。
虛讀:一個事務讀到另一個事務已經提交的insert資料,導致在前一個事務多次查詢結果不一致。
寫問題
引發兩類丟失更新
讀問題的解決
設定事務的隔離級別
read uncommited:以上的讀問題都會發生 1
read commiited:解決髒讀,但是不可重複讀和虛讀有可能發生 2
repeatable read:解決髒讀和不可重複讀,但是虛讀有可能發生 4
serializable:解決所有讀問題 8
1.6.2 HIbernate中設定事務隔離級別
<!-- 核心配置檔案 設定事務隔離級別 -->
<property name="hibernate.connection.isolation">4</property>
1.6.3 Service層事務
Hibernate解決Service的事務管理
改寫工具類
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFaction sf;
static {
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
public static Session openSession(){
return sf.openSession();
}
public static Session getCurrentSession(){
return sf.getCurrentSession();
}
}
配置完成
<!-- hibernate核心配置檔案中 配置當前執行緒繫結的Session -->
<property name="hibernate.current_session_context_class">thread</property>
//測試當前執行緒繫結的Session
public class HibernateDemo4 {
@Test
public void demo1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王西");
session.save(customer);
tx.commit();
}
}
1.7 Hibernate 的其他API
1.7.1 Query
Query介面用於接收HQL,查詢多個物件。
HQL:Hibernate Query Language,這種語言與SQL的語法極其類似
//Hibernate的其他API
public class HibernateDemo5 {
@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.setMaxResullt(3);
List<Customer> list = query.list();
for(Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
}
1.7.2 Criteria
Criteria:QBC(Query By Criteria)
更加面向物件的查詢方式
@Test
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//通過session獲得Criteria的物件
//Criteria criteria = session.createCriteria(Customer.class);
//List<Customer> list = criteria.list();
//條件查詢
//Criteria criteria = session.createCriteria(Customer.class);
//criteria.add(Restrictions.like("cust_name","王%"));
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(3);
criteria.setMaxResults(3);
List<Customer> list = criteria.list();
for(Customer customer : list){
System.out.println(Customer);
}
tx.commit();
}
1.7.3 SQLQuery
SQLQuery用於接收SQL。特別複雜的情況下使用SQL。