1.lazy(true,false):是否延遲加載。通常設為true
          1)由spring容器管理業務層方法a的事務,那么在a中也就是一個事務范圍內(超過了事務范圍就commit了),對象是可以lazyload的,若對象到了表現層由于出了事務的范圍已經commit,session已經關閉了就不能lazyload,若需要在表現層lazyload使用opensessioninview解決。
          2)壓力不大的情況可以使用opensessioninview,壓力教大的情況不要使用延遲加載,開始就初始化填充調用Hibernate.initialize(parent.getChildren())或者parent.getChildren().size()。

          2.get()和load():最主要的區別在于返回的是否是代理對象。通常使用load。
          1)load()取對象時若不使用對應的屬性值,那么返回的是一個代理對象。當session關閉后再取屬性值會報session關閉異常,因此使用此方法時,需要獲取對象的數值時先使用Hibernate.initialize()初始化。此方法還會利用二級緩存。當使用opensessioninview時,不用Hibernate.initialize()初始化,session還未關閉,代理對象還能通過session獲取數值。(跟延遲加載很像)
          2)get()返回的是帶有屬性值的對象。

          3.inverse(true,false):雙向關聯時由“誰”作為主控方來維護“外鍵”。
          1對多雙向關聯通常1控制反轉,讓多方來維護。
          1(parent)對多(children)關系中:
          1)1對應的集合設置inverse為false,表示不控制反轉,也就是1自己作為主控方維護關系,表現在代碼中:parent必須setChildren(),表示parent“知道了”children的信息(但children"不知道"parent信息),此時由1作為主控方維護之間的外鍵。
          s.save(parent)時(已經設置了級聯更新)sql操作:插入parent,插入不帶外鍵的children,更新children外鍵為parent的id;
          2)1對應的集合設置inverse為true,表示控制反轉,也就是”多“作為主控方維護關系,表現在代碼中:parent要setChildren(),每個children也要setParent(),表示children“知道了”parent的信息,即知道了parent的id信息并將其作為自己的外鍵。
          s.save(parent)時(已經設置了級聯更新)sql操作減少為:插入parent,插入帶外鍵的children。
          3)只要設置了inverse必然是雙向關聯,不可能是單向關聯,因為雙向關聯才有互相設置對方的可能:parent.setChildren(),children.setParent()。雙向關聯的雙方類中都必須有對方的對象或對象的集合作為屬性:parent類中必須有children的集合,children類中必須有parent對象。

          多對多雙向關聯通常被動方控制反轉,讓主動方來維護外鍵。
          多(user)對多(role)舉例:
          1)user為主控方,role為被動方。從業務上來分析角色(role)是用戶(user)的一個屬性,而角色相對于用戶來說類似一個數據字典一樣的基礎數據。因此何為主動何為被動是從業務角度去分析。
          2)從業務角度去分析。一般主動方有一個明顯特征是會級聯的更新操作被動方,例如修改用戶信息時會去修改這個人具有的角色。而更新操作被動方時由于角色類似基礎數據,更新的應該是角色其本身的信息,不會在修改角色時還要修改對應的用戶。role——authority這兩者多對多的業務中,role又是主動方,authority是被動方。
          3)多對多雙向必須主動方維護外鍵,否則若讓被動方維護外鍵,在級聯更新,級聯刪除時外鍵將不會得到更新和刪除。

          4.cascade(all-delete-orphan,all,save-update,delete,none):是否需要級聯更新。
          1)save-update:表示級聯增改。
          2)all:表示級聯增刪改。但是在沒設置控制反轉時,刪除僅表示取消關聯(update外鍵NULL,形成孤兒)而不是真正刪除關聯對象。若設置了控制反轉,可以直接刪除,不會形成孤兒。
          3)all-delete-orphan:同all一樣,但刪表示真正刪除。對于上面孤兒,設置此項可真正刪除。
          因此不同情況時孤兒問題的解決方法(外鍵NULL問題):在雙向關聯時盡量使用inverse="true"來避免;在單向關聯時使用all-delete-orphan來刪除孤兒(外鍵已經設置為NULL的記錄)。

          通常:
          ①多對多關系應使用cascade="save-update",例如:user-role多對多,刪除user時不會刪除role,但會刪除userrole關聯表中的關聯記錄。
          ②1對多雙向關聯1這一方設置了<set inverse="true">時應使用cascade="all"。
          ③1對多單向關聯,單向關聯不能設置控制反轉,應使用cascade="all-delete-orphan"。

          5.fetch(select,join):獲取一個對象時,如何獲取非lazy的對象/集合。lazy和fetch是不能同時設置的他們是互斥的,即出現lazy=“true”就不能出現fetch=“xx”;出現fetch=“xx”就不能出現lazy=“true”
          通常在應用中絕大部分的實體或集合,延遲方式抓取數據應該是最佳選擇。對于需要一次性加載對象和關聯集合的情況,一般使用連接抓取(join)或子查詢抓取(subselect)而不使用查詢抓取(select)。
          例如數據字典,權限,角色這種很少改動的數據,可以一次性將其和關聯結合讀到緩存中。
          (1)fetch=“join”,主體對象和關聯對象用一句外鍵關聯的sql同時查詢出來,不會形成多次查詢。僅對get/load有效,對query無效。(1條sql獲取主體與集合:select a,b from table1 left join table2 on table1.pid=table2.fid)
          (2)fetch=“select”,先查詢返回要查詢的主體對象,再根據關聯對象的id,為每一個對象發送一條select查詢,獲取關聯的對象,形成n+1次查詢。(1條sql獲取主體,n條sql獲取集合:select a,b from table where id=?)
          (3)fetch=“subselect”,先查詢返回要查詢的主體對象,再根據關聯外鍵id,為所有對象只發送一條select查詢,獲取關聯的對象。(1條sql獲取主體,1條sql獲取集合:select a,b from table where id in (?,?,?...))


          6.unsaved-value(null):1對多關聯的集合中新增一個pojo,是否持久化到數據庫。通常設為null
          1是po對象,1對多的集合中新增一個pojo,保存1時此集合中的pojo根據其id是否等于null來判斷是否插入db,若等于null表示此對象是transient自有狀態,插入db,若不等于null表示此對象是persistent持久狀態,由hibernate來管理他是否要更新。

          7.dynamic-update,dynamic-insert(true,false):生成update,insert的sql語句時是否包含null字段。通常設為true
          運行時比較屬性動態生成sql,無法利用sql緩存的preparedStatement,所以適合大容量遠程數據庫,不適合小型數據庫。但是1,2級緩存還是能夠提高性能的。

          8.cache usage:hibernate二級緩存的事務策略。通常使用下面的前3個
          1)使用read-only:應用程序只需讀取一個持久化類的實例,而無需對其修改。例如省份,城市等數據字典。
          2)使用nonstrict-read-write:如果應用程序只偶爾需要更新數據,也就是說,兩個事務同時更新同一記錄的情況很不常見,也不需要十分嚴格的事務隔離。例如user—role—privilege—resource權限管理中的privilege,resource是僅僅會偶爾更改的。
          3)使用read-write:如果應用程序需要更新數據但不頻繁(頻繁修改不應該緩存)。例如user—role—privilege—resource權限管理中的user,role是會較少更改的。
          4)使用transactional:對事務要求苛刻的系統例如金融,這樣的緩存只能用于JTA環境中,ehCache不支持此策略。

          9.id的generator:通常使用native,identity。
          (1)uuid.hex:按一定算法生成的數值,幾乎不可能重復。性能好。但主鍵是字符型而不是數值型。
          (2)native:hibernate根據db自動選擇是identity還是sequence等等。方便db遷移,適合db多變的系統。
          (3)sequence:數據庫提供的sequence生成。app先select獲取主鍵再insert。效率非常低,尤其是在大數據量插入時。
          (4)identity:數據庫提供的autoincrement生成。db內部先讀主鍵+1再insert。
          (5)increment:應用程序提供的autoincrement生成。多個app維護自己的主鍵,同時insert同一個db時可能主鍵重復。
          (6)assigned:業務邏輯生成,而上述都有hibernate自動生成,id滲透業務。

          10.fetch-size,batch-size:對較大數據量的數據進行操作,此參數影響性能明顯。通常都設為50。
          1)fetch-size:查時buffer緩沖區大小,每次查詢到達緩沖區大小時才返回一次數據。讀1w條記錄,不設參數則讀1w次,設參數為50則只讀200次。每批傳輸的條數增大(1條變為50條),那么傳輸的次數減少(1w次變為200次),若是appServer和dbServer兩臺機器間網絡傳輸,此參數對性能提高更明顯。
          2)batch-size:增刪改時buffer緩沖區大小。每次增刪改到達緩沖區大小時才提交一次數據。道理同上。
          3)mysql不支持,mssql,oracle都支持。此參數并非越大越好,50以上性能可能還會下降,因為每批維護的buffer緩存區過大。
          4)用spring配置hibernate的sessionFactory時集中配置hibernate.jdbc.fetch_size和hibernate.jdbc.batch_size,而不必在各個bean中配置。

          11.set,list,bag:通常有重復記錄用List,沒有重復記錄用Set。
          1)set:a—b(1對多或多對多)業務斷定b沒有重復元素則使用set。不保持持久化的元素順序。
          2)list:a—b(1對多或多對多)業務斷定b會有重復元素則使用list。保持持久化的元素順序。但表中要增加一個字段用來表示順序。
          3)bag,是一個可重復的set,不保持持久化的元素順序。本希望即可重復又不用添加一個字段,但是其性能低下不要使用。(插入集合數據到db時,先刪除所有集合數據,再將現有數據逐條插入)

          12.max_fetch_depth:為單向關聯(一對一, 多對一)的外連接抓取(fetch=“join”)抓取最大深度。1對多不起作用。通常讓其默認為0,不用管他。
          1)對于應用中絕大部分的實體或集合,延遲方式抓取數據應該是最佳選擇。也就是說通常對象或集合的加載方式都是lazy的,一次性fetch抓取對象和其關聯的集合/對象只在特殊場合使用(例如:相互關聯的數據需要緩存,則一次性讀取),此參數使用范圍很小。
          2)若需要一次讀取3層關聯的所有數據,可以通過代碼循環先讀取一邊。

          13.save(),update(),saveOrUpdate(),merge():對象是持久態,那么對象值的所有改變都由容器管理保存到db,否則要通過調用函數顯示告知容器保存到db
          (1)對象由自由態pojo轉成持久態po,用save(obj)。
          (2)對象由持久態po轉成游離態是pojo后,修改對象值后希望再持久化轉成持久態po,用update(obj);此作用不是用來更新db,而是將obj納入了容器。
          (3)不知道對象是自由態pojo還是游離態pojo,都希望持久化轉成持久態po,用saveOrUpdate(obj),例如表現層接到業務層傳來的一個obj做修改并保存,但不知道是哪個狀態的,保存時使用saveOrUpdate()。
          (4)對象是po(持久態的),那么修改其值后,不用顯示調用save,update,saveOrUpdate任何一個函數即可在事務提交時自動將改動保存到db,因為在commit的時候由容器管理并將改動保存到db中。
          (5)merge與saveOrUpdate()一樣,都能將自由對象和游離對象持久化,區別在于:在session中存在兩個對象,但具有同一個標識(即主鍵),那么hibernate容器在持久化時不知道該持久化哪一個,一般會拋出那個經典的hibernate異常(NonUniqueObjectException)。merge字面意思是“合并”,其作用在于:將其中一個對象的屬性合并到另外一個對象中,然后持久化后一個對象。
          兩個對象有同一個標識的場景(使用merge場景):①在save一個對象user1之前(游離態或持久態的,已經納入hibernate容器的管理,session中已經緩存此對象),又根據user1的id去session.load一個新對象user2進行業務操作(例如待更新對象和db對象比較),結果導致session中存在兩user對象具有相同id(save和load在一個事務中)。②session.load一個對象user1,對象傳遞時,將此對象的所有屬性包括id賦值給另一個對象user2,session.update()對象user2,那么user2也納入hibernate的容器管理即此時session中也存在兩user對象具有相同id(load和update在一個事務中)。
          既然了解了場景,我們完全可以自己解決(只不過hibernate提供merge統一解決):①中session.load一個新user2進行業務操作后,關閉session,并evit()session中的新user2,再update那個user1,此時session中只存在一個user1具有id,即不會發生異常。②中避免更新user2,可以將user2中修改的屬性值設置到user1中,然后更新user1,因為user2只是一個pojo還沒有納入hibernate容器的管理,所以session中只存在user1。


          14.Criteria和Query:一般在單對象(單表)多條件查詢時使用Criteria,多對象(多表)多條件查詢時用Query。
          1)Criteria:單表多條件的查詢,可以封裝統一處理各種比較條件,不用對不同對象的查詢都寫一次比較條件,
          例如Restrictions.eq,le,lt,ge,gt,like的封裝統一處理。
          2)Query:對于多表關聯查詢時,使用hql更方便。

          15.query.list()和query.iterator():一般類似基礎數據這樣需要緩存的數據,在appServer啟動時就讀到二級緩存中,我們使用list讀。一般在程序中讀數據時若確定此數據是被緩存的,那么使用iterator,否則還是使用list讀。
          1)list:缺點在于不能利用二級緩存,但可填充二級緩存。優點在于查詢sql語句就一條。
          2)iterator:優點在于可以利用二級緩存,也能填充二級緩存。缺點在于當緩存中找不到時,先1條sql獲取id,再根據id每條每條sql的查詢,n+1查詢。所以使用前要認定數據已緩存。

          16.hibernate容器管理:
          (1)持久態是po:若一個對象和關聯的對象都納入容器的管理即都是po,那么其值的所有改變都由容器管理保存到db,而不用通過配置來告訴容器如何保持到db。
          (2)自由態,游離態是pojo:若一個對象或者其關聯的集合中對象是pojo,那么我們就要通過一些配置來告訴容器怎么管理,因為是pojo純對象沒有納入容器的管理范圍,容器是不知道如何操作這個對象的,例如插入“1”時是否需要級聯插入“多”集合中新增的對象,我們配置unsaved-value為null,那么容器將比較集合對象的id和null來決定是否插入。


          17.clear,evit,delete。
          ①clear():清除所有緩存,不清除db,將持久態——>游離態。一般較少使用,通常用在批量操作時,清空session緩存,防止內存緊張。
          ②evit(entity):清除某個緩存,不清除db,將持久態——>游離態。一般較少使用,通常使用場合同上。還有就是對已經load到session中的對象,業務決定再次load希望強制更新,但是load會使用緩存,因此可以先evit()開始那個對象。
          ③delete(entity):清除某個緩存,清除db,將持久態——>自由態。

          18.查詢n+1
          ①非懶加載的load/get查詢時(對query無效),fetch="select"會形成n+1查詢(會利用二級緩存),使用fetch="join"一條語句解決(不利用二級緩存)
          ②query.iterator()時,會形成n+1查詢(會利用二級緩存),使用query.list()一條語句解決(不利用二級緩存)
          可以看出n+1次查詢的好處是利用二級緩存,所以就是使用場景的問題:
          當確定數據一定緩存時可以n+1次到ram中查(例如數據字典在系統啟動時初始化到ram)。
          當不確定數據一定緩存時應一條語句查詢。
          posted on 2010-11-15 11:37 hello 閱讀(660) 評論(0)  編輯  收藏 所屬分類: hibernate
          主站蜘蛛池模板: 莫力| 陇西县| 苍梧县| 大港区| 延川县| 仙桃市| 周口市| 成都市| 金昌市| 专栏| 沁源县| 辰溪县| 沙雅县| 昔阳县| 南昌市| 微山县| 越西县| 崇仁县| 海门市| 金平| 兴海县| 出国| 吐鲁番市| 潞城市| 大厂| 米脂县| 邵武市| 思南县| 嘉定区| 呈贡县| 淮滨县| 乡宁县| 绥阳县| 历史| 灵川县| 班玛县| 崇礼县| 桦南县| 清远市| 万载县| 白城市|