一掩宜、首先新建一個項(xiàng)目
其他的與上一次的項(xiàng)目差不多相同砾赔,只不過date的改為java.util.date的
測試類中的修改如圖所示
刪除hibernate數(shù)據(jù)庫的所有表蝌箍,然后運(yùn)行該測試類,得到新的表暴心,表結(jié)構(gòu)如下:
二妓盲、Session 概述
(1)Session 接口是 Hibernate 向應(yīng)用程序提供的操縱數(shù)據(jù)庫的最主要的接口,它提供了基本的保存, 更新, 刪除和加載 Java 對象的方法专普。
(2)Session 具有一個緩存悯衬,位于緩存中的對象稱為持久化對象,它和數(shù)據(jù)庫中的相關(guān)記錄對應(yīng). Session 能夠在某些時(shí)間點(diǎn)檀夹,按照緩存中對象的變化來執(zhí)行相關(guān)的 SQL 語句筋粗,來同步更新數(shù)據(jù)庫, 這一過程被稱為刷新緩存(flush)。
(3)站在持久化的角度炸渡,Hibernate 把對象分為 4 種狀態(tài):持久化狀態(tài)娜亿,臨時(shí)狀態(tài),游離狀態(tài)蚌堵,刪除狀態(tài)买决。Session 的特定方法能使對象從一個狀態(tài)轉(zhuǎn)換到另一個狀態(tài)。
三吼畏、Session 緩存
(1)在 Session 接口的實(shí)現(xiàn)中包含一系列的 Java 集合, 這些 Java 集合構(gòu)成了 Session 緩存. 只要 Session 實(shí)例沒有結(jié)束生命周期, 且沒有清理緩存督赤,則存放在它緩存中的對象也不會結(jié)束生命周期。
(2)Session 緩存可減少 Hibernate 應(yīng)用程序訪問數(shù)據(jù)庫的頻率宫仗。
從上圖可以看出只發(fā)送一條sql够挂。
四、flush 緩存
(1)flush:Session 按照緩存中對象的屬性變化來同步更新數(shù)據(jù)庫藕夫。
(2)默認(rèn)情況下 Session 在以下時(shí)間點(diǎn)刷新緩存:
????①顯式調(diào)用 Session 的 flush() 方法孽糖。
????②當(dāng)應(yīng)用程序調(diào)用 Transaction 的 commit()方法時(shí), 該方法先 flush 枯冈,然后在向數(shù)據(jù)庫提交事務(wù)。
????③當(dāng)應(yīng)用程序執(zhí)行一些查詢(HQL, Criteria)操作時(shí)办悟,如果緩存中持久化對象的屬性已經(jīng)發(fā)生了變化尘奏,會先 flush 緩存,以保證查詢結(jié)果能夠反映持久化對象的最新狀態(tài)病蛉。
(3)flush 緩存的例外情況: 如果對象使用 native 生成器生成 OID炫加,那么當(dāng)調(diào)用 Session 的 save() 方法保存對象時(shí),會立即執(zhí)行向數(shù)據(jù)庫插入該實(shí)體的 insert 語句铺然。
(4)commit() 和 flush() 方法的區(qū)別:flush 執(zhí)行一系列 sql 語句俗孝,但不提交事務(wù);commit 方法先調(diào)用flush() 方法魄健,然后提交事務(wù)赋铝。提交事務(wù)意味著對數(shù)據(jù)庫操作永久保存下來。
五沽瘦、設(shè)定刷新緩存的時(shí)間點(diǎn)
若希望改變 flush 的默認(rèn)時(shí)間點(diǎn), 可以通過 Session 的 setFlushMode() 方法顯式設(shè)定 flush 的時(shí)間點(diǎn) 革骨。
知識點(diǎn)擴(kuò)展:Hibernate的FlushMode與session.flush()
Hibernate session FlushMode有五種屬性:
1、NEVEL:已經(jīng)廢棄了析恋,被MANUAL取代了
2良哲、MANUAL:
如果FlushMode是MANUAL或NEVEL,在操作過程中hibernate會將事務(wù)設(shè)置為readonly,所以在增加助隧、刪除或修改操作過程中會出現(xiàn)如下錯誤org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition筑凫;
解決辦法:配置事務(wù),spring會讀取事務(wù)中的各種配置來覆蓋hibernate的session中的FlushMode喇颁;
3漏健、AUTO
設(shè)置成auto之后,當(dāng)程序進(jìn)行查詢橘霎、提交事務(wù)或者調(diào)用session.flush()的時(shí)候,都會使緩存和數(shù)據(jù)庫進(jìn)行同步殖属,也就是刷新數(shù)據(jù)庫
4姐叁、COMMIT
提交事務(wù)或者session.flush()時(shí),刷新數(shù)據(jù)庫洗显;查詢不刷新
5外潜、ALWAYS:
每次進(jìn)行查詢、提交事務(wù)挠唆、session.flush()的時(shí)候都會刷數(shù)據(jù)庫
ALWAYS和AUTO的區(qū)別:當(dāng)hibernate緩存中的對象被改動之后处窥,會被標(biāo)記為臟數(shù)據(jù)(即與數(shù)據(jù)庫不同步了)。當(dāng) session設(shè)置為FlushMode.AUTO時(shí)玄组,hibernate在進(jìn)行查詢的時(shí)候會判斷緩存中的數(shù)據(jù)是否為臟數(shù)據(jù)滔驾,是則刷數(shù)據(jù)庫谒麦,不是則不刷,而always是直接刷新哆致,不進(jìn)行任何判斷绕德。很顯然auto比always要高效得多。
六摊阀、數(shù)據(jù)庫的隔離級別
(1)對于同時(shí)運(yùn)行的多個事務(wù)耻蛇,當(dāng)這些事務(wù)訪問數(shù)據(jù)庫中相同的數(shù)據(jù)時(shí),如果沒有采取必要的隔離機(jī)制胞此,就會導(dǎo)致各種并發(fā)問題:
①臟讀:對于兩個事物 T1臣咖、T2,T1 讀取了已經(jīng)被 T2 更新但還沒有被提交的字段漱牵。之后亡哄,若 T2 回滾,T1讀取的內(nèi)容就是臨時(shí)且無效的布疙。
②不可重復(fù)讀:對于兩個事物 T1蚊惯、 T2,T1 讀取了一個字段灵临,然后 T2 更新了該字段截型。之后,T1再次讀取同一個字段儒溉,值就不同了宦焦。
③幻讀:對于兩個事物 T1、T2顿涣,T1 從一個表中讀取了一個字段波闹,然后 T2 在該表中插入了一些新的行。之后涛碑,如果 T1 再次讀取同一個表精堕,就會多出幾行。
(2)數(shù)據(jù)庫事務(wù)的隔離性:數(shù)據(jù)庫系統(tǒng)必須具有隔離并發(fā)運(yùn)行各個事務(wù)的能力蒲障,使它們不會相互影響歹篓,避免各種并發(fā)問題。
(3)一個事務(wù)與其他事務(wù)隔離的程度稱為隔離級別揉阎。數(shù)據(jù)庫規(guī)定了多種事務(wù)隔離級別庄撮,不同隔離級別對應(yīng)不同的干擾程度,隔離級別越高毙籽,數(shù)據(jù)一致性就越好洞斯,但并發(fā)性越弱。
(4)數(shù)據(jù)庫提供的 4 種事務(wù)隔離級別:
Oracle 支持的 2 種事務(wù)隔離級別:READ COMMITED, SERIALIZABLE坑赡。Oracle 默認(rèn)的事務(wù)隔離級別為:READ COMMITED
Mysql 支持 4 中事務(wù)隔離級別. Mysql 默認(rèn)的事務(wù)隔離級別為:REPEATABLE READ
七烙如、在 MySql 中設(shè)置隔離級別
(1)每啟動一個 mysql 程序么抗,就會獲得一個單獨(dú)的數(shù)據(jù)庫連接。每個數(shù)據(jù)庫連接都有一個全局變量 @@tx_isolation厅翔,表示當(dāng)前的事務(wù)隔離級別乖坠。MySQL 默認(rèn)的隔離級別為 Repeatable Read。
(2)查看當(dāng)前的隔離級別: SELECT @@tx_isolation;
(3)設(shè)置當(dāng)前 mySQL 連接的隔離級別:
set transaction isolation level read committed;
(4)設(shè)置數(shù)據(jù)庫系統(tǒng)的全局的隔離級別:
set global transaction isolation level read committed;
八刀闷、在 Hibernate 中設(shè)置隔離級別
(1)JDBC 數(shù)據(jù)庫連接使用數(shù)據(jù)庫系統(tǒng)默認(rèn)的隔離級別熊泵。 在 Hibernate 的配置文件中可以顯式的設(shè)置隔離級別。每一個隔離級別都對應(yīng)一個整數(shù):
***1. READ UNCOMMITED
***2. READ COMMITED
***4. REPEATABLE READ
***8. SERIALIZEABLE
(2)Hibernate 通過為 Hibernate 映射文件指定 hibernate.connection.isolation 屬性來設(shè)置事務(wù)的隔離級別甸昏。
九减江、reflesh()和hibernate的事務(wù)隔離級別的例子
(1)打斷點(diǎn)先打印一次
(2)修改數(shù)據(jù)庫
(3)運(yùn)行完曼验,打印結(jié)果一樣,author沒變
(4)設(shè)置hibernate的事務(wù)隔離級別
(5)重新運(yùn)行該方法
(6)修改數(shù)據(jù)庫的AUTHOR為SUN
(7)運(yùn)行結(jié)束,最后的打印是最新的
十炕倘、持久化對象的狀態(tài)
站在持久化的角度喧锦,Hibernate 把對象分為 4 種狀態(tài):持久化狀態(tài)辆童、臨時(shí)狀態(tài)抒痒、游離狀態(tài)、刪除狀態(tài)修械;Session 的特定方法能使對象從一個狀態(tài)轉(zhuǎn)換到另一個狀態(tài)趾牧。
(1)臨時(shí)對象(Transient):
在使用代理主鍵的情況下, OID 通常為 null
不處于 Session 的緩存中
在數(shù)據(jù)庫中沒有對應(yīng)的記錄
(2)持久化對象(也叫”托管”)(Persist):
OID 不為 null
位于 Session 緩存中
若在數(shù)據(jù)庫中已經(jīng)有和其對應(yīng)的記錄, 持久化對象和數(shù)據(jù)庫中的相關(guān)記錄對應(yīng)
Session 在 flush 緩存時(shí), 會根據(jù)持久化對象的屬性變化, 來同步更新數(shù)據(jù)庫
在同一個 Session 實(shí)例的緩存中, 數(shù)據(jù)庫表中的每條記錄只對應(yīng)唯一的持久化對象
(3)刪除對象(Removed)
在數(shù)據(jù)庫中沒有和其 OID 對應(yīng)的記錄
不再處于 Session 緩存中
一般情況下, 應(yīng)用程序不該再使用被刪除的對象
(4)游離對象(也叫”脫管”) (Detached):
OID 不為 null
不再處于 Session 緩存中
一般情況需下, 游離對象是由持久化對象轉(zhuǎn)變過來的, 因此在數(shù)據(jù)庫中可能還存在與它對應(yīng)的記錄
十一、對象的狀態(tài)轉(zhuǎn)換圖
十一肯污、Session 的 save() 方法
(1)Session 的 save() 方法使一個臨時(shí)對象轉(zhuǎn)變?yōu)槌志没瘜ο?/p>
(2)Session 的 save() 方法完成以下操作:
把 News 對象加入到 Session 緩存中, 使它進(jìn)入持久化狀態(tài)
選用映射文件指定的標(biāo)識符生成器, 為持久化對象分配唯一的 OID. 在 使用代理主鍵的情況下, setId() 方法為 News 對象設(shè)置 OID 是無效的.
計(jì)劃執(zhí)行一條 insert 語句:在 flush 緩存的時(shí)候
(2)Hibernate 通過持久化對象的 OID 來維持它和數(shù)據(jù)庫相關(guān)記錄的對應(yīng)關(guān)系翘单。當(dāng) News 對象處于持久化狀態(tài)時(shí), 不允許程序隨意修改它的 ID。
(3)persist() 和 save() 區(qū)別:
當(dāng)對一個 OID 不為 Null 的對象執(zhí)行 save() 方法時(shí), 會把該對象以一個新的 oid 保存到數(shù)據(jù)庫中;? 但執(zhí)行 persist() 方法時(shí)會拋出一個異常:蹦渣。
案例:
(1)先把該對象的主鍵生成方式改為hilo
(2)編寫測試
(3)設(shè)置ID是無效的
(4)當(dāng) News 對象處于持久化狀態(tài)時(shí), 不允許程序隨意修改它的 ID
(5)peisist方法
十二哄芜、Session 的 get() 和 load() 方法
(1)都可以根據(jù)跟定的 OID 從數(shù)據(jù)庫中加載一個持久化對象
(2)區(qū)別:
當(dāng)數(shù)據(jù)庫中不存在與 OID 對應(yīng)的記錄時(shí), load() 方法拋出 ObjectNotFoundException 異常, 而 get() 方法返回 null;
兩者采用不同的延遲檢索策略:load 方法支持延遲加載策略柬唯。而 get 不支持认臊。
(3)執(zhí)行g(shù)et()方法:會立即加載對象;執(zhí)行l(wèi)oad方法:若不使用該對象权逗,則不會立即執(zhí)行查詢操作美尸,而返回一個代理對象。
(4)若數(shù)據(jù)庫中沒有對應(yīng)記錄斟薇,且Session也沒有被關(guān)閉,get返回Null恕酸;load若不使用該對象的任何屬性堪滨,沒問題,若需要初始化了蕊温,拋出異常袱箱。
(5)load方法可能會拋出懶加載異常:在需要初始化代理對象之前已經(jīng)關(guān)閉了Session
十三遏乔、Session 的 update() 方法
(1)Session 的 update() 方法使一個游離對象轉(zhuǎn)變?yōu)槌志没瘜ο螅⑶矣?jì)劃執(zhí)行一條 update 語句发笔。若希望 Session 僅當(dāng)修改了 News 對象的屬性時(shí)盟萨,才執(zhí)行 update() 語句,可以把映射文件中 元素的 select-before-update 設(shè)為 true了讨,該屬性的默認(rèn)值為 false捻激。
(2)當(dāng) update() 方法關(guān)聯(lián)一個游離對象時(shí), 如果在 Session 的緩存中已經(jīng)存在相同 OID 的持久化對象, 會拋出異常。
(3)當(dāng) update() 方法關(guān)聯(lián)一個游離對象時(shí), 如果在數(shù)據(jù)庫中不存在相應(yīng)的記錄前计,也會拋出異常胞谭。.
示例:
①、若更新一個持久化對象男杈,不需要顯示的調(diào)用update方法丈屹,因?yàn)檎{(diào)用Transaction的commot方法時(shí),會執(zhí)行session的flush方法伶棒。
十四旺垒、Session 的 saveOrUpdate() 方法
Session 的 saveOrUpdate() 方法同時(shí)包含了 save() 與 update() 方法的功能。
判定對象為臨時(shí)對象的標(biāo)準(zhǔn):
①肤无、Java 對象的 OID 為 null先蒋;
②、映射文件中為 設(shè)置了 unsaved-value 屬性, 并且 Java 對象的 OID 取值與這個 unsaved-value 屬性值匹配舅锄。
(1)執(zhí)行insert語句
(2)若OID不為空鞭达,但數(shù)據(jù)表還沒有和其對應(yīng)的記錄,會拋出一個異常皇忿;如果有其對應(yīng)的記錄畴蹭,則更新。
十五鳍烁、Session 的 delete() 方法
(1)Session 的 delete() 方法既可以刪除一個游離對象, 也可以刪除一個持久化對象叨襟;
(2)Session 的 delete() 方法處理過程:
①、計(jì)劃執(zhí)行一條 delete 語句幔荒;
②糊闽、把對象從 Session 緩存中刪除,該對象進(jìn)入刪除狀態(tài)爹梁。
(3)Hibernate 的 cfg.xml 配置文件中有一個 hibernate.use_identifier_rollback 屬性, 其默認(rèn)值為 false, 若把它設(shè)為 true, 將改變 delete() 方法的運(yùn)行行為:delete() 方法會把持久化對象或游離對象的 OID 設(shè)置為 null右犹,使它們變?yōu)榕R時(shí)對象。
示例1:
示例2:
示例3:
十六姚垃、Session 的 evict() 方法
從session緩存中把指定的持久化對象移除念链。
十七、通過 Hibernate 調(diào)用存儲過程
(1)Work 接口:直接通過 JDBC API 來訪問數(shù)據(jù)庫的操作;
(2)Session 的 doWork(Work) 方法用于執(zhí)行 Work 對象指定的操作掂墓,即調(diào)用 Work 對象的 execute() 方法谦纱。Session 會把當(dāng)前使用的數(shù)據(jù)庫連接傳遞給 execute() 方法。
十八君编、Hibernate 與觸發(fā)器協(xié)同工作
(1)Hibernate 與數(shù)據(jù)庫中的觸發(fā)器協(xié)同工作時(shí)跨嘉,會造成兩類問題:
①、觸發(fā)器使 Session 的緩存中的持久化對象與數(shù)據(jù)庫中對應(yīng)的數(shù)據(jù)不一致:觸發(fā)器運(yùn)行在數(shù)據(jù)庫中, 它執(zhí)行的操作對 Session 是透明的吃嘿;
②祠乃、Session 的 update() 方法盲目地激發(fā)觸發(fā)器: 無論游離對象的屬性是否發(fā)生變化, 都會執(zhí)行 update 語句, 而 update 語句會激發(fā)數(shù)據(jù)庫中相應(yīng)的觸發(fā)器。
(2)解決方案:
①唠椭、在執(zhí)行完 Session 的相關(guān)操作后跳纳,立即調(diào)用 Session 的 flush() 和 refresh() 方法,迫使 Session 的緩存與數(shù)據(jù)庫同步(refresh() 方法重新從數(shù)據(jù)庫中加載對象)贪嫂。
②寺庄、在映射文件的的 元素中設(shè)置 select-before-update 屬性:當(dāng) Session 的 update 或 saveOrUpdate() 方法更新一個游離對象時(shí),會先執(zhí)行 Select 語句力崇,獲得當(dāng)前游離對象在數(shù)據(jù)庫中的最新數(shù)據(jù), 只有在不一致的情況下才會執(zhí)行 update 語句斗塘。