Hibernate持久化類編寫的規則
一、持久化類的概述
1、什麼是持久化類
持久化:將內存當中的一個對象持久化到數據庫當中的過程。Hibernate框架就是用來進行持久化的框架。
持久化類:一個Java對象與數據庫的表建立了映射關係,那麼這個類在Hibernate當中就可以稱爲持久化類
持久化類 = Java類 + 映射文件
二、持久化類的編寫規則
1、持久化類的編寫規則
(1)對持久化類提供一個無參數的構造方法 :Hibernate底層需要通過反射來生成實例
例如:
(2)對屬性需要私有,對私有屬性提供共有的get和set方法 :Hibernate當中要獲取,設置這個對象的值。
(3)對持久化類通過一個唯一的標識OID與數據庫的主鍵對應:Java當中通過對象的地址來區分是否是同一個對象,數據庫當中通過主鍵來確定是否是同一個記錄,在Hibernate當中通過持久化類的OID的屬性來區分是否是同一個對象。
(4)持久化類當中的屬性儘量要使用包裝類的類型。Integer Long Double :因爲基本數據類型的默認值是0,那麼這個0就會有很多的歧義。(包裝類的類型默認是null)
(5)持久化類不要使用final進行修飾:延遲加載本身是Hibernate的一個優化的手段。返回的是一個代理對象(Javassist可以對沒有實現接口的類來產生代理—使用了十分底層的字節碼增強的技術來,繼承這個類進行代理,如果該類使用final就不能被繼承,也就不能產生代理對象,延遲加載也就失效了,Hibernate的優化也就失效了,load方法就會和get方法變得一樣)。
測試該特性
public final class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
public Customer() {
// TODO Auto-generated constructor stub
}
public Customer(Long cust_id, String cust_name, String cust_source, String cust_industry, String cust_level,
String cust_phone, String cust_mobile) {
super();
this.cust_id = cust_id;
this.cust_name = cust_name;
this.cust_source = cust_source;
this.cust_industry = cust_industry;
this.cust_level = cust_level;
this.cust_phone = cust_phone;
this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + ", cust_source=" + cust_source+ ", cust_industry=" + cust_industry + ", cust_level=" + cust_level + ", cust_phone=" + cust_phone+ ", cust_mobile=" + cust_mobile + "]";
}
}
並且這時返回的對象是真實的對象不是代理對象
@Test
// 查詢:
public void demo02() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();// 創建數據庫事務對象開啓事務
// 使用load方法查詢
Customer customer = session.load(Customer.class, 2l);
System.out.println(customer);
tx.commit();// 提交事務// load方法發送SQL語句
session.close();
}
使用Debug模式測試代碼
三、主鍵生成策略
1、主鍵的分類:
A、自然主鍵
自然主鍵:主鍵的本身就是表當中的一個字段(實體當中的具體的屬性)。
a、創建一個人員表、人員都會有一個身份證號(唯一的不可重複的),使用了身份證號作爲主鍵的,這種主鍵就稱爲的自然主鍵。
B、代理主鍵:主鍵的本身不是表中必須的一個字段(不是實體當中某個具體的屬性)。
a、創建一個人員表,沒有使用人員當中的身份證號,用了一個與這個表不相關的字段ID,(PND)。這種主鍵稱爲代理主鍵。
b、在實際的開發當中,儘量要使用代理主鍵。
c、一旦自然主鍵參與到業務邏輯當中。後期就有可能修改源代碼。(好的程序的設計要滿足OCP原則:對程序的一個擴展是open的。對修改原碼是close的)
2、Hibernate的主鍵生成策略
在實際開發中一般是不允許用戶手動設置主鍵,一般會將主鍵數據庫,手動編寫程序進行設置。
在hibernate當中爲了減少程序的編寫,提供了很多的主鍵生成的策略。
A、increment:hibernate中提供的一個自動增長的一個機制。(mysql當中不會選自動增長,使用的Hibernate當中的)適用於short,int,long類型的主鍵。
在單線程的程序當中使用
a、首先發送一條語句,select max(id) from 查到表id:然後讓id+1作爲下一條記錄的一個記錄的主鍵。
B:identity:適用於short、int、long類型的主鍵,使用的是數據庫底層的自動增長的機制。適用於有自動增長機制的數據庫(MySQL,MSSQL)但是Oracle沒有找到增長機制的。
C:sequnence:序列 適用於short、int、long類型的主鍵,採用的是序列的方式。(Oracle支持序列)。MySQL就不能使用sequnence
D : uuid:適用於字符串主鍵。使用Hibernate當中一種隨機方式生成字符串類型的主鍵
E:native:本地策略,可以在identity和sequnence之間來進行自動切換
F:assigned:Hibernate會放棄外鍵的管理,需要通過自己手動編寫程序或者用戶自己進行設置。
G:foreign:外部的。一對一的一種關聯映射的情況下使用。(例如兩個表的主鍵是一一對應的)
3、上述主鍵生成策略的案例
A、increment:
在映射文件當中修改對應的生成鍵策略對應的class
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sf;
static {
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
public static Session openSession() {
return sf.openSession();
}
}
public class HibernateDemo1 {
@Test
// 保存一條記錄
//演示increment
public void demo01() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王細");
session.save(customer);
transaction.commit();
session.close();
}
@Test
// 保存一條記錄
//演示increment
public void demo02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王被");
session.save(customer);
transaction.commit();
session.close();
}
}
1、使用Debug模式分別調試兩個方法,分別在不同的線程當中調試
當第一個方法執行時
會先查詢表當中的id的值,然後加1
將對應的屬性的值放入到加1的id對應的表的項內
此時將數據插入到對應的表當中後,不提交事務
2、開始用第二個方法
會先查詢表當中的id的值,然後加1
將對應的屬性的值放入到加1的id對應的表的項內
對應相同的id上插入對應的數據,然後會報錯
B:identity:
在映射文件當中修改對應的生成鍵策略對應的class
@Test
// 保存一條記錄
//演示identity
public void demo03() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王被");
session.save(customer);
transaction.commit();
session.close();
}
使用數據庫的自動增長機制
D : uuid:
將Customer的id改爲String類型的
在映射文件當中修改對應的生成鍵策略對應的class
@Test
// 保存一條記錄
//演示uuid
public void demo04() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王被");
session.save(customer);
transaction.commit();
session.close();
}
F:assigned:
在映射文件當中修改對應的生成鍵策略對應的class
直接執行會報錯,因爲,沒有設置主鍵的值,需要手動設置
@Test
// 保存一條記錄
//演示assigned
public void demo05() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_id(4556L);
customer.setCust_name("王被");
session.save(customer);
transaction.commit();
session.close();
}
一般用native和identity的比較多(int Long 的主鍵)
映射文件當中
四、持久化類的三種狀態
Hibernate是持久層的一個框架,通過持久化類完成ORM操作。Hibernate爲了更好的管理持久化類,就將持久化類分爲三種狀態。
持久化類=Java類+映射
1、瞬時態:沒有持久化標識OID,沒有被納入Session對象的管理
這種對象沒有唯一的標識OID,沒有被session所管理。
2、持久態:有持久化標識OID,已經被納入Session對象的管理
這種對象有唯一的標識OID,被session所管理,這種對象就是持久態的對象。
持久化類的持久態對象。可以自動更新數據庫,
3、託管態:有持久化標識OID,但沒有被Session對象管理
這種對象有唯一標識的OID,沒有被session管理,這個就稱爲託管態的對象。
區分這三種狀態的對象
五、Hibernate持久化類的三種狀態轉換
三種狀態轉換圖
1:瞬時態的對象
A :獲得瞬時態對象
獲得:將與表建立好映射的類,new創建該類的對象,就創建了session的瞬時太對象
在這裏爲
Customer customer = new Customer();
B:狀態轉換
瞬時態,可以轉換成爲持久態(瞬時態->持久態)
save(Object obj);//通過save方法將瞬時態轉換成爲持久態
saveOrUpdate(Object obj);
瞬時太,可以轉換成爲託管態(瞬時太->託管態)
customer.setCust_id(1);//對象設置了id
2:持久態的對象
A :獲得持久態對象
get(Object.class,id);
Customer customer = session.get(Customer.class,1L);//直接獲得持久態對象
load(Object.class,id);
Customer customer = session.load(Customer.class, 2l);
find(Object.class,id);
Customer customer = session.find(Customer.class, 2l);
iterate(Object.class,id);
Customer customer = session.iterate(Customer.class, 2l);
B:狀態轉換
持久態,可以轉換成爲瞬時態(持久態->瞬時態)
delete();、
session.delete(Object obj);
持久態,可以轉換成爲託管態(持久態->託管態)
close();
session.close();
clear();
session.clear();
evict(Object obj);
session.evict();
3:託管態的對象
A :獲得託管態對象
Customer customer = new Customer();
customer.setCust_id(1L);
B:狀態轉換
託管態,可以轉換成爲持久態(託管態->持久態)
update(Object obj);
session.update(Object obj);
saveOrUpdate(Object obj);
session.saveOrUpdate(Object obj);
託管態,可以轉換成爲瞬時態(託管態->瞬時態)
Customer customer = new Customer();
customer.setCust_id(null);
六、Hibernate持久態對象特性
1、持久化類的持久態對象自動更新數據庫
@Test
// 持久態對象可以自動更新數據庫----》依賴了Hibernate裏面的一級緩存
public void demo02() {
Session session = HibernateUtils.openSession();// 鏈接數據庫開啓session域
Transaction transaction = session.beginTransaction();// 開啓事務
//獲得持久態對象
Customer customer = session.get(Customer.class, 1l);//持久態對象可以自動更新數據庫
//當對應更改的數據與數據庫當中的數據不同的時候,就不會更改數據庫當中的數據
//當對應數據的數據與數據庫當中的數據不同的時候就會更改其中的數據
customer.setCust_name("王南");
//這裏可以不用去更新數據庫
//session.update(customer);
transaction.commit();
session.close();// 關閉session對象,銷燬對象
}