Hibernate使用Java 反射機制 而不是字節碼加強程序來實現透明性java
若是JDBC代碼寫的完美,優化作好,那麼JDBC效率是最高的。可是,實際開發中很是不現實,對程序員要求過高。
通常狀況下,hibernate內部進行了JDBC的優化處理,以及增長緩存機制,大大提升了運行效率。程序員
SessionFactory使用要點以下:
一、負責建立Session對象,能夠經過Configuration對象建立SessionFactory對象
二、SessionFactory 對象中保存了當前的數據庫配置信息和全部映射關係以及預約義的SQL語句。
三、SessionFactory還負責維護Hibernate的二級緩存。
四、SessionFactory對象的建立會有較大的開銷,並且SessionFactory對象採起了線程安全的設計方式,所以在實際中SessionFactory對象能夠儘可能的共享,在大多數狀況下,一個應用中針對一個數據庫能夠共享一個SessionFactory實例
SessionFactory只能有一個(單例模式或者變爲static屬性)web
Session是持久化操做的基礎。Session的設計是非線程安全的,所以,一個Session對象只能夠由一個線程使用。面試
使用Hibernate進行操做時(增、刪、改)必須顯示的調用Transaction(默認:autoCommit=false)
Transaction transaction = session.beginTransaction();
transaction.commit();算法
處於持久化狀態的對象,當發生值得改變時,hibernate能檢測到,馬上修改數據庫的數據。若是在save以後,執行sql語句,效率較低。建議對持久對象值進行修改在save以前最好spring
//若對應id=1的記錄不存在,返回null;
//get方法先在session緩存(一級緩存)中查找,若無,再在sessionfacotory(二級緩存)中查找,若無,再去數據庫中查找,還無,返回null.
User u = (User) s.get(User.class, 1);
//若對應id=1的記錄不存在,則拋出異常。
//load通常用於咱們能夠保證這個記錄必定存在的狀況。該方法有懶加載!
User u = (User) s.load(User.class, 1);sql
一對多:
通常使用雙向關聯
cascade屬性:級聯操做。操做一個對象時將該對象相關屬性對象也進行一樣操做。
all:進行任何操做都級聯。
save-update:保存和更新操做時
delete:刪除操做時級聯
all-delete-orpnan:當被關聯對象失去宿主時,將其級聯刪除。
none(默認) :不級聯數據庫
inverse屬性:由哪一方維護外鍵的值。默認爲false, 雙方均可以維護關聯關係; 爲true, 則表示由「多方」維護;
建議:
爲true, 由多方維護提升效率。調用必須調用「多方」(通常由多方維護)。
爲false,寫程序方便,運行效率低下。
Inverse=false,關聯關係能夠由雙方維護!
可是咱們通常將關聯關係交給」多方」來維護。上面兩次實驗,第一次交給了多方維護,執行了3條SQL語句。第二交給了一方維護,執行了3條insert語句和2條update語句(假如增長200個僱員那麼就會有200個update語句)。若是咱們交給一方來維護,顯然會有多餘的SQL語句執行,從而下降了效率。所以,咱們通常建議關聯關係由多方維護!那麼這時候,咱們能夠強制經過inverse=true,指定由多方維護!設計模式
一對一關係咱們通常採用惟一外鍵關聯!數組
多對多:
多對多的實體關係模型也是很常見的,好比學生和課程的關係。一個學生能夠選修多門課程,一個課程能夠被多名學生選修。在關係型數據庫中對於多對多關聯關係的處理通常採用中間表的形式,將多對多的關係轉化成兩個一對多的關係。
性能優化:
注意session.clear()的運用,尤爲在不斷分頁循環的時候,會產生另一種形式的內存泄露 ( //面試題:Java有內存泄漏嗎?語法級別沒有 可是可由java引發,例如:鏈接池不關閉,或io讀取後不關閉)
面試題:
一、open session每次都是新的,須要手動close
getCurrentsession從上下文找,若是有,用舊的,若是沒有,建新的
若是你正在查詢,使用的openSession而沒有手動關閉,屢次以後會致使鏈接池溢出
二、get load的區別:
load返回的是代理對象,等到真正用到對象的內容時才發出sql語句
get則返回的是實體對象,直接從數據庫加載,不會延遲
get請求的對象數據庫中沒有時返回null,load則拋異常。
總之對於get和load的根本區別,一句話,hibernate對於load方法認爲該數據在數據庫中必定存在,能夠放心的使用代理來延遲加載,若是在使用過程當中發現了問題,只能拋異常;而對於get方法,hibernate必定要獲取到真實的數據,不然返回null。
session.clear();:不管是load仍是get,都會首先査找緩存(一級緩存),若是沒有,纔會去數據庫査找,調用clear()方法能夠強制清除session緩存
三、transient:內存中有一個新new的對象JavaBean,緩存(即session)中沒有指向new對象的Map,跟數據庫也沒有關係(數據庫沒對應記錄的存在)
persistent:save()完後爲persistent狀態,內存中有JavaBean(生成了Id),以map形式存入到session中 ,數據庫中有對應記錄
detached:session.close()後(但session.close()方法不會顯示調用,在session.commit()時系統自動close),緩存中清空,跟session無關,數據庫有對應記錄,可是數據庫和內存中的對象沒有鏈接到一塊兒,因此叫作detached託管的。
四、雙向關聯關係的兩鐵律:
凡是雙向關聯,必設mappedBy
在程序中也要A.set(B)以及B.set(A)
五、繼承映射:
單表繼承(整個類繼承結構一個表)
優勢:只有一張表,操做方便,效率高。
缺點:冗餘數據多,增長子類要修改表結構,數據多時表很是大。
joined-subclass(父類映射成表,一個類一張表,互相關聯,不獨立)
優勢:冗餘字段少,表結構合理(關係模型設計上優良)
缺點:多態查詢慢(通常不要用,最好直接指定類型。好比查詢man,則會把man的子類表也查一遍)、查詢須要外鏈接
union-subclass (父類不映射成表,每一個子類一張表,互不關聯,獨立)
優勢:表都獨立利於移植,查詢不用外鏈接速度快
缺點:數據庫包含重複字段過多,包含了父類中的字段
注意:父類和子類id不能重複,用自動遞增不行,可用increment/hilo/uuid等。
如何選用?(通常使用joined-subclass)
若是子類屬性很少,總數據量不大,選用單表繼承
若是子類屬性較多,可用joined-subclass.
union-subclass用的不多
六、hibernate的樹狀結構:前面有介紹
七、1+N問題:
在一個對象中關聯了另外一個對象,同時FetchType爲Eager,好比說最典型的ManyToOne(固然OneToMany也有這問題,當在Many這頭設Eager),默認Many方是FetchType爲Eager,當取Many裏的對象時,會單獨再發一條SQL語句將他關聯的對象也取出來,即原本只要發一條SQL,結果發了1+N條, 解決方案:fetch=FetchType.LAZY,還能夠用Join fetch(在1方,查找獲得了n個對象, 那麼又須要將n個對象關聯的集合取出,因而原本的一條sql查詢變成了n+1條。)
二級緩存
在對象更新,刪除,添加相對於查詢要少得多時, 二級緩存的應用將不怕n+1問題,由於即便第一次查詢很慢,以後直接緩存命中也是很快的,恰好又利用了n+1。
八、三種緩存:
一級緩存( Session緩存)
一級緩存的管理 : 應用程序調用Session的save()、update()、saveOrUpdate()、get()或load(),以及調用查詢接口的 list()、iterate() 時,若是在Session緩存中還不存在相應的對象,Hibernate 就會把該對象加入到第一級緩存中。 能夠經過close/clear/evict清空緩存
一級緩存的做用 : 由於Session的生命期每每很短,存在於Session內部的第一級最快緩存的生命期固然也很短,因此第一級緩存的命中率是很低的。其對系統性能的改善也是頗有限的。Session內部緩 存的主要做用是保持Session內部數據狀態同步。
二級緩存(SessionFactory緩存):需手動開啓
開啓方式:
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
如何使用: 類定義前面:@cache,指該類的對象都會放入二級緩存。@Cache(usage=CacheConcurrencyStrategy.READ_WRITE) //放入二級緩存中也能夠被修改。通常用它。
什麼內容時候放入二級緩存: 常常被訪問、改動不頻繁、數量有限。
get/load會使用二級緩存。
iterate也會使用二級緩存。
list默認會往二級緩存中存放數據,即經過list查出的結果會放入二級緩存。可是list自己查詢時不會使用二級緩存。
查詢緩存:
查詢緩存只對query.list()起做用
查詢緩存依賴於二級緩存,所以必定要打開二級緩存。
查詢緩存實現機制:以查詢語句爲key,查到的對象的id爲value
查詢緩存的配置和使用:
開啓二級緩存:
<property name="hibernate.cache.use_query_cache">true</property> //默認是fasle
在程序中必須手動啓用查詢緩存,如:query.setCacheable(true);
緩存算法問題:緩存滿了後,將內存中哪一個對象清掉。
LRU:Least Recently Used 最近最少被使用的。每一個緩存對象都記錄一個最後使用時間。
LFU:Least Frequently Used 最近使用頻率最少。
FIFO:First In First Out
九、事務基本概念
ACID便是atomicity(原子性),consistency(一致性),isolation(隔離性)和durability(持久性)的首字母的縮寫
原子性:表示一個事務內的全部操做是一個總體,要 麼所有成功,要麼全失敗;
一致性:表示一個事務內有一個操做失敗時,全部的更改過的數據都必須回滾到修改前的狀態;
隔離性:事務查看數據時數據所處的狀態,要麼是另外一併發事務修改它以前的狀態,要麼是另外一事務修改它以後的狀態,事務不會查看中間狀態的數據。
持久性:事務完成以後,它對於系統的影響是永久性的。
事務隔離級別從低到高:
讀取未提交(Read Uncommitted)
讀取已提交(Read Committed)
可重複讀(Repeatable Read)
序列化(serializable)
read-commited(讀取已提交的數據 項目中通常都使用這個)不會出現dirty read,由於只有另外一個事務提交纔會讀出來結果,但仍然會出現 non-repeatable read 和 phantom-read
使用read-commited機制可用悲觀鎖 樂觀鎖來解決non-repeatable read 和 phantom-read問題
咱們通常採用讀取已提交,配合各類併發訪問控制策略來達到併發事務控制的目的。
十、樂觀鎖與悲觀鎖
樂觀鎖Optimistic Locking:
顧名思義就是保持一種樂觀的態度,咱們認爲系統中的事務併發更新不會很頻繁,即便衝突了也沒事,大不了從新再來一次。
它的基本思想就是每次提交一個事務更新時,咱們想看看要修改的東西從上次讀取之後有沒有被其它事務修改過,若是修改過,那麼更新就會失敗。
經常使用實現方法:
在咱們的實體中增長一個版本控制字段,每次事務更新後就將版本(Version)字段:版本字段的值加1.
在實體類中增長@Version, private int version;getset 便可。
悲觀鎖Pessimistic Locking:
基本思想就是每次一個事務讀取某一條記錄後,就會把這條記錄鎖住,這樣其它的事務要想更新,必須等之前的事務提交或者回滾解除鎖。
悲觀鎖的實現,每每依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,不然,即便在本系統中實現了加鎖機制,也沒法保證外部系統不會修改數據)
樂觀鎖和悲觀鎖的比較:
樂觀鎖:
優點:併發性好,性能較高。
缺點:用戶體驗很差,錄入了半天,提交時被告知已經修改!
悲觀鎖:
優點:會鎖住記錄,一個用戶修改完成前,其餘用戶不能操做該記錄。
缺點:併發性很差,性能不高。
對於悲觀鎖是針對併發的可能性比較大,而通常在咱們的應用中用樂觀鎖足以。
Hibernate實踐總結
一、數據量巨大,性能要求高,hibernate因爲在ORM映射中對系統資源消耗也比較高,因此不適合。
二、Hibernate適合:邏輯複雜,數據量不大。
三、sessionFactory的建立很是消耗資源,整個應用通常只要一個。
四、將全部的集合屬性配置設置爲懶加載。 Hibernate2.x默認是false, hibernate3.x默認是true
五、在定義關聯關係時,集合首選Set,若是集合中的實體存在重複,則選擇List,數組性能最差。
六、在一對多的雙向關聯中,通常將集合(多)的inverse設置爲true,讓集合的對方維護關聯關係。
七、HQL子句自己大小寫無關,可是其中出現的類名和屬性名必須注意大小寫區分。
八、對大數據量查詢時,慎用list() 返回查詢結果
九、在性能瓶頸的地方使用JDBC。
十、使用雙向關聯。在大型應用中,幾乎全部的關聯必須在查詢中能夠雙向導航。
Hibernate工做原理及爲何要用?
原理:
1.讀取並解析配置文件
2.讀取並解析映射信息,建立SessionFactory
3.打開Sesssion
4.建立事務Transation
5.持久化操做
6.提交事務
7.關閉Session
8.關閉SesstionFactory
爲何要用:
1. 對JDBC訪問數據庫的代碼作了封裝,大大簡化了數據訪問層繁瑣的重複性代碼。
2. Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現。他很大程度的簡化DAO層的編碼工做
3. hibernate使用Java反射機制,而不是字節碼加強程序來實現透明性。
4. hibernate的性能很是好,由於它是個輕量級框架。映射的靈活性很出色。它支持各類關係數據庫,從一對一到多對多的各類複雜關係。
2. Hibernate是如何延遲加載?
1. Hibernate2延遲加載實現:a)實體對象 b)集合(Collection)
2. Hibernate3 提供了屬性的延遲加載功能;當Hibernate在查詢數據的時候,數據並無存在與內存中,當程序真正對數據的操做時,對象才存在與內存中,就實現了延遲加載,他節省了服務器的內存開銷,從而提升了服務器的性能。
3.Hibernate中怎樣實現類之間的關係?(如:一對多、多對多的關係)
類與類之間的關係主要體如今表與表之間的關係進行操做,它們都市對對象進行操做,咱們程序中把全部的表與類都映射在一塊兒,它們經過配置文件中的many-to-one、one-to-many、many-to-many、
4. 說下Hibernate的緩存機制
1. 內部緩存存在Hibernate中又叫一級緩存,屬於應用事物級緩存
2. 二級緩存:
a) 應用及緩存
b) 分佈式緩存
條件:數據不會被第三方修改、數據大小在可接受範圍、數據更新頻率低、同一數據被系統頻繁使用、非 關鍵數據
c) 第三方緩存的實現
5. Hibernate的查詢方式
Sql、Criteria,object comptosition
Hql:
一、 屬性查詢
二、 參數查詢、命名參數查詢
三、 關聯查詢
四、 分頁查詢
五、 統計函數
6. 如何優化Hibernate?
1.使用雙向一對多關聯,不使用單向一對多
2.靈活使用單向一對多關聯
3.不用一對一,用多對一取代
4.配置對象緩存,不使用集合緩存
5.一對多集合使用Bag,多對多集合使用Set
6. 繼承類使用顯式多態
7. 表字段要少,表關聯不要怕多,有二級緩存撐腰
7. Struts工做機制?爲何要使用Struts?
工做機制:
Struts的工做流程:
在web應用啓動時就會加載初始化ActionServlet,ActionServlet從
struts-config.xml文件中讀取配置信息,把它們存放到各類配置對象
當ActionServlet接收到一個客戶請求時,將執行以下流程.
-(1)檢索和用戶請求匹配的ActionMapping實例,若是不存在,就返回請求路徑無效信息;
-(2)若是ActionForm實例不存在,就建立一個ActionForm對象,把客戶提交的表單數據保存到ActionForm對象中;
-(3)根據配置信息決定是否須要表單驗證.若是須要驗證,就調用ActionForm的validate()方法;
-(4)若是ActionForm的validate()方法返回null或返回一個不包含ActionMessage的ActuibErrors對象, 就表示表單驗證成功;
-(5)ActionServlet根據ActionMapping所包含的映射信息決定將請求轉發給哪一個Action,若是相應的 Action實例不存在,就先建立這個實例,而後調用Action的execute()方法;
-(6)Action的execute()方法返回一個ActionForward對象,ActionServlet在把客戶請求轉發給 ActionForward對象指向的JSP組件;
-(7)ActionForward對象指向JSP組件生成動態網頁,返回給客戶;
爲何要用:
JSP、Servlet、JavaBean技術的出現給咱們構建強大的企業應用系統提供了可能。但用這些技術構建的系統很是的繁亂,因此在此之上,咱們須要一個規則、一個把這些技術組織起來的規則,這就是框架,Struts便應運而生。
基於Struts開發的應用由3類組件構成:控制器組件、模型組件、視圖組件
8. Struts的validate框架是如何驗證的?
在struts配置文件中配置具體的錯誤提示,再在FormBean中的validate()方法具體調用。
9. 說下Struts的設計模式
MVC 模式: web應用程序啓動時就會加載並初始化ActionServler。用戶提交表單時,一個配置好的ActionForm對象被建立,並被填入表單相應的數據,ActionServler根據Struts-config.xml文件配置好的設置決定是否須要表單驗證,若是須要就調用ActionForm的 Validate()驗證後選擇將請求發送到哪一個Action,若是Action不存在,ActionServlet會先建立這個對象,而後調用 Action的execute()方法。Execute()從ActionForm對象中獲取數據,完成業務邏輯,返回一個ActionForward對象,ActionServlet再把客戶請求轉發給ActionForward對象指定的jsp組件,ActionForward對象指定的jsp生成動態的網頁,返回給客戶。
10. spring工做機制及爲何要用?
1.spring mvc請全部的請求都提交給DispatcherServlet,它會委託應用系統的其餘模塊負責負責對請求進行真正的處理工做。
2.DispatcherServlet查詢一個或多個HandlerMapping,找處處理請求的Controller.
3.DispatcherServlet請請求提交到目標Controller
4.Controller進行業務邏輯處理後,會返回一個ModelAndView
5.Dispathcher查詢一個或多個ViewResolver視圖解析器,找到ModelAndView對象指定的視圖對象
6.視圖對象負責渲染返回給客戶端。
爲何用:{AOP 讓開發人員能夠建立非行爲性的關注點,稱爲橫切關注點,並將它們插入到應用程序代碼中。使用 AOP 後,公共服務 (比 如日誌、持久性、事務等)就能夠分解成方面並應用到域對象上,同時不會增長域對象的對象模型的複雜性。IOC 容許建立一個能夠構造對象的應用環境,而後向這些對象傳遞它們的協做對象。正如單詞 倒置 所代表的,IOC 就像反 過來的 JNDI。沒有使用一堆抽象工廠、服務定位器、單元素(singleton)和直接構造(straight construction),每個對象都是用其協做對象構造的。所以是由容器管理協做對象(collaborator)。Spring即便一個AOP框架,也是一IOC容器。 Spring 最好的地方是它有助於您替換對象。有了 Spring,只要用 JavaBean 屬性和配置文件加入依賴性(協做對象)。而後能夠很容易地在須要時替換具備相似接口的協做對象。}