Hibernate快速筆記1
路線:
- Hibernate的概述,原理,簡單的API使用
- 一級快取和其他API
- 1vN和NvN的配置
- Hibernate的查詢方式和抓取策略
- CRM案例
引入:CRM系統【百度百科】
客戶關係管理系統(CRM)是以客戶資料的管理為核心,利用資訊科學技術,實現市場營銷、銷售、服務等活動自動化,並建立一個客戶資訊的收集、管理、分析、利用的系統,幫助企業實現以客戶為中心的管理模式。客戶關係管理既是一種管理理念,又是一種軟體技術。
客戶關係管理系統主要有高可控性的資料庫、更高的安全性、資料實時更新等特點,提供日程管理、訂單管理、發票管理、知識庫管理等功能。
客戶關係一對一理論。滿足每個客戶的特殊需求,同每個客戶建立聯絡,通過同客戶的聯絡來了解客戶的不同需求,並在此基礎上進行"一對一"個性化服務。
從新客戶接入到老客戶維護和營銷的每一個環節。與銷售、營銷、推廣、策劃、人事等多部門業務對接。優化各業務環節,減少各環節客戶流失,和公司成本。----------市場營銷、資料分析、掌控能力等
CRM系統是一種綜合性的概念,這樣的系統一般就是面向客戶的資料資訊,可以分為若干模組。如客戶資訊管理、聯絡人管理、統計分析、綜合查詢等。
簡單解釋,銷售方業務員工(使用者)使用這種系統,先去找到客戶方的某些代表的聯絡人(聯絡人管理),通過他們開發成客戶,並記錄這個過程中的資訊(客戶拜訪管理),然後把客戶的資料錄入系統(客戶資訊管理),然後可以隨時通過系統查詢上述這些所有的資訊(綜合查詢),進而進行一些相應的分析處理(統計分析)。 另外,這個系統本身還有一些基本的管理和使用,比如賬戶、日誌等(系統管理)。
本案例僅涉及CRM中客戶資訊管理的CRUD操作及配置
Hibernate是什麼?怎麼用?
框架是一種軟體的半成品,未完全加工。
經典的JAVA EE(服務端)分為Web、業務、持久三層結構。不同的技術和框架對應著不同的層次,這是在長期經驗下的產物,或者說建議。使用傳統的 Servlet + Jsp + JavaBean + JDBC 可以完成開發,但是框架的好處是加快快發效率,效能更加優越。
常用架構對應的分層示意圖:![圖一 EE的三層結構](assets/圖一 EE的三層結構2.bmp)
總結:持久層中的ORM框架,對JDBC進行了輕量級封裝,自動化。ORM也就是物件關係對映,將Java中的物件和資料庫的表通過xml做對映,達到操作物件就是直接操作表
優點:1)對JDBC的輕量級封裝,簡化資料訪問層的重複性程式碼,減少記憶體消耗,提高效率
2)框架,優秀的ORM實現,簡化DAO(Data Access Object)層的實現
3)效能強,擴充套件性強——多種RDB,多種ER關係對映;可拓展,多種API,開源。【注】:效能高是相對的,一般來說越底層的訪問速率是越快的,而上層的提供了許多方便的拓展使用方法,進行了一些優化,達到提升效能的結果。
版本:3.x(5.x類似,相容),4.x
使用:
- [下載](<https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/)檔案,解壓;
- 解壓檔案目錄中包含doc(文件),lib(庫),project(預設專案);其中lib中含有必須和非必須的各種庫檔案(jar包)
- 建立Java專案或者WEB專案時均可引用,使用的方式就是導JAR包;
- 資料庫操作的JAR包:資料庫驅動如 MySQL,JDBC/C3P0等
- lib中的required中的包
- 日誌記錄包log4j——便於開發
方式
-
建立資料表
-
建立實體類
-
使用hbm.xml(命名隨意,但約定字尾),配置對映關係
<?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> <!-- 建立類與表的對映 --> <class name="com.itheima.hibernate.demo1.Customer" table="cst_customer"> <!-- 建立類中的屬性與表中的主鍵對應 --> <id name="cust_id" column="cust_id" > <generator class="native"/> </id> <!-- 建立類中的普通的屬性和表的欄位的對應 --> <property name="cust_name" column="cust_name" length="32" /> <property name="cust_source" column="cust_source" length="32"/> <property name="cust_industry" column="cust_industry"/> <property name="cust_level" column="cust_level"/> <property name="cust_phone" column="cust_phone"/> <property name="cust_mobile" column="cust_mobile"/> </class> </hibernate-mapping>
-
Hibernate的全域性配置cfg.xml,配置的說明在解壓檔案下l\project\etc\hibernate.properties中有示例
- 配置資料庫:驅動,伺服器,埠號,資料庫
- Hibernate方言
- 資料庫連線池
- 匯入對映檔案
配置檔案
-
對映配置檔案 ------xxx.hbm.xml
-
<hibernate-mapping>下配置所有
-
<class>/<id>/<property>標籤
-
欄位:name,column等,length在hibernate自動建表時使用
-
【class標籤的配置】
-
標籤用來建立類與表的對映關係
-
屬性:
-
name :類的全路徑
-
table :表名(類名與表名一致,table可以省略)
-
catalog :資料庫名
-
【id標籤的配置】
-
標籤用來建立類中的屬性與表中的主鍵的對應關係
-
屬性:
-
name :類中的屬性名
-
column :表中的欄位名(類中的屬性名和表中的欄位名如果一致,column可以省略)
-
length :長度
-
type :型別
-
【property標籤的配置】
-
標籤用來建立類中的普通屬性與表的欄位的對應關係
-
屬性:
-
name :類中的屬性名
-
column:表中的欄位名
-
length :長度
-
type :型別
-
not-null :設定非空
-
unique :設定唯一
-
-
-
-
hibernate核心配置 hibernate.cfg.xml
- <hibernate-configuration>下配置所有,注:配置同樣可以使用properties檔案配置,但是這樣載入不了對映檔案
- <session-factory>配置會話工廠,相當於配置不同的連線容器,用來解析後建立不同的連線池,包含多個連線,也就是session
- 資料庫的配置(驅動,DB,賬戶,密碼等) 【必須】
- 方言配置——控制不同的資料庫會話 【必須】
- 對映檔案<mapping> , 也可以使用手動載入
- 【可選】SQL語句的列印(console)與格式化,自動建立表——用作測試和驗證
- 顯示SQL :hibernate.show_sql
格式化SQL :hibernate.format_sql
自動建表 :hibernate.hbm2ddl.auto- none:不使用hibernate的自動建表
- create:如果資料庫中已經有表,刪除原有表,重新建立,如果沒有表,新建表。(測試)
- create-drop :如果資料庫中已經有表,刪除原有表,執行操作,刪除這個表。如果沒有表,新建一個,使用完了刪除該表。(測試)
- update:如果資料庫中有表,使用原有表,如果沒有表,建立新表(更新表結構)
- validate :如果沒有表,不會建立表。只會使用資料庫中原有的表。(校驗對映和表結構)。
- 顯示SQL :hibernate.show_sql
核心API (幾個物件)
-
Configuration: 載入核心配置檔案,對映配置檔案(手動載入);用來配置Hibernate,啟動Hibernate;啟動時對映到不同的xml檔案,然後建立SessionFactory物件。
-
SessionFactory:初始化hibernate,資料來源的代理(相當於連線池),session的工廠,使用Configuration建立;維護hibernate的資料庫連線池和二級快取(已基本棄用);執行緒安全的,一個專案只需一個;也可以手動配置另外的如C3P0連線池(需匯入相應的jar包)
- 於是,可以在一個專案中,使用一個工具類,抽取出相應的Session工廠;
- 同一個專案使用一個工廠即可,用來返回不同的session
-
Session:Session代表的是Hibernate與資料庫的連結物件,類似於connection。不是執行緒安全的,所有一般會獲取多個,單獨使用。與資料庫互動的橋樑。具有一批方法,來進行CRUD操作:
-
儲存:Serializable save(Object obj); 返回序列化的鍵——序號
-
查詢:T get(Class c,Serializable id); T load(Class c,Serializable id);
get和load的區別:get是立即執行傳送SQL,返回查詢到的物件或者null;load懶載入,使用物件的時候才執行查詢的SQL(除了ID可以直接獲取外);
get返回是真實物件,load返回的是代理物件(javassist),物件不存在的時候報錯
-
修改:void update(Object obj);直接修改(相同ID的新物件替代),先查詢再修改
-
刪除:void delete(Object obj);根據刪除(相同ID序號的新物件),先查詢再刪除,支援Hibernate的級聯刪除
-
【不常用】儲存或更新:void saveOrUpdate(Object obj)
-
【不常用】查詢所有: Query createSQLQuery(String sql) 同樣支援HQL createQuery()
-
-
Transaction:事務物件,commit、rollback
基礎筆記(案例一、基於Hibernate的DAO操作)
-
持久化與持久化類
Hibernate是持久層的ORM對映框架,專注於資料的持久化工作——也就是記憶體資料永久性地寫入到資料庫中。Java中與資料庫表中完成對應的對映類檔案,稱為持久化類——或者說帶有對映檔案的Java類物件。
- 持久化類的規則
- 必須有一個無參的建構函式:Hibernate使用反射來生成例項物件,類的class位元組碼需要;
- 私有屬性必須有get/set方法,Hibernate設定物件的值
- 類中必須一個和表主鍵對應的屬性——唯一性
- 類中屬性儘量使用包裝型別,如Integer,Long——基本資料型別的預設值是0,存在歧義,例如int型的年齡,入DB的是0,是0還是忘了插入?
- 類不用final進行修飾——與延遲載入有關,延遲載入是Hibernate的一種優化,返回的是代理物件,其底層用到了繼承,這樣一來會使延遲載入失效,而返回真實物件
- 持久化類的規則
-
Hibernate主鍵生成策略
- 自然主鍵:表本身中的一個欄位,具有實際意義,如身份證號,手機號
- 代理主鍵:表本身不是必須的,與個體的屬性沒有太大關聯,如序列號,Cid,Sid等;【推薦使用】
- 原則:開閉原則,對拓展是開放的,對修改時封閉的
- 生成策略:Hibernate提供多種主鍵的生成策略,不需要使用者自己操作
- increment:Hibernate的自增長,適用於short、int、long等型別主鍵,單執行緒使用;select max(ID) from 表,然後加1作為下一條記錄,存線上程安全問題
- identity:資料庫底層的自增長,不會產生執行緒安全問題,適用於short/int/long等,適用於有自增長的資料庫產品,oracle不行
- sequence:適用於short、int、long等型別主鍵,適用含有序列的資料庫,MySQL不支援
- uuid:字串型別主鍵,Hibernate隨機生成
- native:本地策略,可以視作在identity和sequence自動切換
- assigned:Hibernate不設定主鍵,需要手動插入
- foreign:外部,一對一的一種關聯情況下使用
-
持久化類的三種狀態
- 瞬時態:沒有唯一的標識OID,沒有被session管理
- 持久態:有唯一標識OID,被session管理
- 脫管態:有唯一標識OID,不被session管理;new 物件後,設定ID即可;將ID置為null,則轉為瞬時態;
- 持久化類:**可以自動更新資料庫;**Hibernate的一級快取,也就是資料庫資料的備份,儲存在記憶體中
- 一級快取,和session控制,生命週期與session一致;Hibernate預設自帶與開啟;用於減少對資料庫的訪問;呼叫session集合中的方法時,先訪問快取,沒有則訪問資料庫,然後將其載入到一級快取中。呼叫close()時,關閉session的快取內容,clear()情況所有快取,evict(object)清楚單個物件
- 二級快取,需要手動開啟,暫時不常用;
- 自動更新資料庫:通過Hibernate快取和快照實現,如果快取和快照區資料不同了,那麼就會將快取更新到資料庫中(事務提交時)。
-
事務
事務ACID,由隔離性引發的問題——讀和寫。
讀問題:髒讀、不可重複讀、幻(虛)讀
寫問題:引發兩類丟失更新
-
事務隔離級別
- read-un-commit: 未提交讀
- read-commited:讀已提交 Oracle預設
- repeatable read:重複讀 MySQL預設
- Serializable:序列化
-
Hibernate的隔離級別配置:核心配置檔案cfg.xml中,
<property name="hibernate.connection.isolation">1/2/4/8</property>
-
在開發中,DAO層負責單個的執行邏輯,對業務而言,service層才是處理事務的邏輯;這需要在事務的處理過程中,多個DB操作使用的是同一個連線物件(connection/session)。兩種解決方法:1.向下傳遞同一個session物件;2. 使用ThreadLocal執行緒進行事務操作的繫結。
Hibernate的事物執行緒繫結,需要配置
<property name="hibernate.current_session_context_class">thread/jta等</property>
;配置完後即可在service包含的多個DAO操作中,通過獲取當前執行緒中已繫結的session物件,完成;繫結執行緒後的session不需要再進行手動關閉,執行緒結束後自動關閉;
-
-
其他API
-
query:查詢操作,接受HQL,查詢多個物件,返回唯一結果等
示例:
public void demo4() { //Query Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //查詢所有 String hql = "from Customer"; Query query = session.createQuery(hql); List<Customer> list = query.list(); // for (Customer customer : list) { // System.out.println(customer); // } //條件查詢 // String hql2 = "from Customer where cust_name like ?"; // Query query2 = session.createQuery(hql2); // query2.setParameter(0, "1%"); // list = query2.list(); // for (Customer customer : list) { // System.out.println(customer); // } //分頁查詢 String hql3 = "from Customer"; Query query3 = session.createQuery(hql3); //起點 query3.setFirstResult(2); //size query3.setMaxResults(1); list = query3.list(); for (Customer customer : list) { System.out.println(customer); } transaction.commit(); }
-
Criteria:面向物件查詢,QBC查詢
public void demo() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //查詢所有 Criteria criteria = session.createCriteria(Customer.class); List<Customer> list = criteria.list(); //條件查詢 //criteria.add(Restrictions.like("cust_name", "1%")); List<Customer> list2 = criteria.list(); //分頁 criteria.setFirstResult(0); criteria.setMaxResults(2); List<Customer> list3 = criteria.list(); for (Customer customer : list3) { System.out.println(customer); } transaction.commit(); }
-
SQLQuery:SQL的查詢,一般不常用
-
一對多的關係
案例:CRM中的客戶和聯絡人
- 配置:一端和多端的實體都要使用實體物件的引用進行關係的關聯;在各自的對映配置檔案中,也需要使用關聯的配置
- 級聯操作:測試中,1的物件需要新增多的引用,多的集合要將1新增進來;沒有在配置檔案中配置級聯儲存或更新,則需要兩端同時儲存;否則儲存了主體物件即可,也不需要配置雙向的關聯關係。
- 級聯刪除:刪除1,多方參考的外來鍵置為null(預設);設定了1的級聯刪除,則刪除時同時刪除關聯的多方;也可以設定多方的級聯,刪除時同時刪除關聯的1方資料,且和1方關聯的多方的其他資料也會刪除(基本不用)
- cascade和inverse的區別:前者設定的是物件間的關聯關係,後者管理的是鍵的管理關係;預設一方的inverse為false,表示不放棄外來鍵的管理權。置為True後,儲存1方的物件,會儲存其關聯(cascade)的多方物件入庫,但是卻沒有外來鍵
多對多的關係
- 多對多的關係,需要配置兩個實體外,還需要一個關聯表
- 如果進行的是雙向關聯,二者必須有一個放棄外來鍵的控制,否則關聯表中將會出現主鍵重複的衝突;非雙向關聯則不會出現錯誤
- 級聯儲存或更新:設定後可以只儲存主體一方,否則出現瞬時物件異常;設定級聯後不需要雙向關聯
- 級聯刪除:【基本不用】沒有設定級聯刪除時,只會刪除本表和關聯表;設定cascade後,會將關聯的表中資料一併刪除
一對一的關係
- 一般轉化為唯一外來鍵對應
- 或直接主鍵對應