日期:2023-05-10 20:36:21 來(lái)源:博客園
上一篇咱們介紹了 Hibernate 以及寫了一個(gè) Hibernate 的工具類,快速入門體驗(yàn)了一波 Hibernate 的使用,我們只需通過 Session 對(duì)象就能實(shí)現(xiàn)數(shù)據(jù)庫(kù)的操作了。
(資料圖片)
現(xiàn)在,這篇介紹使用 Hibernate 進(jìn)行基本的 CRUD、懶加載以及緩存的知識(shí)。
基本的 CRUD提示:如果你還沒看上一篇,那么建議你看完上一篇再來(lái)看這篇。
上一篇:一文快速入門體驗(yàn) Hibernate
插入操作以下代碼均寫在測(cè)試類 HibernateTest 中
這個(gè)在上一篇已經(jīng)演示過,這里便不再演示。
查詢操作查詢有 2 種方式,通過 Session 對(duì)象的 get
方法 或者 load
方法來(lái)實(shí)現(xiàn)查詢,主要將查詢的數(shù)據(jù)結(jié)果封裝到一個(gè) Java 對(duì)象中。
get
方法@Test public void queryByGet() { // 獲取 Session 對(duì)象 Session session = HibernateUtil.getSession(); try { // 使用 get() 方法,第一個(gè)參數(shù)是持久化類的類型參數(shù),第二個(gè)參數(shù)是主鍵標(biāo)識(shí)參數(shù),如果沒有匹配的記錄,那么會(huì)返回 null User user = session.get(User.class, new Integer("1")); System.out.println("用戶ID:" + user.getId()); } catch (Exception e) { System.out.println("查詢User數(shù)據(jù)失?。?); e.printStackTrace(); } finally{ // 關(guān)閉 Session 對(duì)象 HibernateUtil.closeSession(); } }
控制臺(tái)輸出:可以看到,執(zhí)行了查詢 SQL,并打印了用戶 ID。
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect五月 08, 2023 11:38:59 下午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateServiceINFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_, user0_.password as password3_0_0_ from user user0_ where user0_.id=?用戶ID:1
load
方法@Test public void queryByLoad() { // 獲取 Session 對(duì)象 Session session = HibernateUtil.getSession(); try { // 使用 load() 方法,它返回對(duì)象的代理,只有該代理被調(diào)用時(shí),Hibernate 才會(huì)真正去執(zhí)行 SQL 查詢 User user = session.load(User.class, new Integer("1")); // ID 是已知的,不用進(jìn)行查詢 System.out.println("用戶ID:" + user.getId()); // 此時(shí)該代理被調(diào)用,就執(zhí)行 SQL 語(yǔ)句,得到真正的數(shù)據(jù)記錄 System.out.println("用戶名稱:" + user.getName()); } catch (Exception e) { System.out.println("查詢User數(shù)據(jù)失??!"); e.printStackTrace(); } finally{ // 關(guān)閉 Session 對(duì)象 HibernateUtil.closeSession(); } }
控制臺(tái)輸出:
五月 08, 2023 11:40:13 下午 org.hibernate.dialect.Dialect INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect五月 08, 2023 11:40:14 下午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateServiceINFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]用戶ID:1Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_, user0_.password as password3_0_0_ from user user0_ where user0_.id=?用戶名稱:god23bin
可以看到,是先打印用戶ID的,這里還沒有執(zhí)行查詢 SQL,直到下一條語(yǔ)句中的 user.getName()
的執(zhí)行,查詢的 SQL 語(yǔ)句才被 Hibernate 執(zhí)行。
想對(duì)某條數(shù)據(jù)進(jìn)行修改操作,那么需要將它先查詢出來(lái),然后進(jìn)行修改。這里就執(zhí)行了兩條 SQL,保險(xiǎn)起見,開啟事務(wù),然后執(zhí)行這兩條 SQL,接著提交事務(wù)。當(dāng)然,這兩條 SQL,Hibernate 幫我們寫的啦!
@Test public void update() { // 獲取 Session 對(duì)象 Session session = HibernateUtil.getSession(); try { // 開啟事務(wù) session.beginTransaction(); // 進(jìn)行查詢,將結(jié)果封裝成 user 對(duì)象 User user = session.get(User.class, new Integer("1")); // 對(duì) user 對(duì)象進(jìn)行修改 user.setName("公眾號(hào):god23bin"); user.setPassword("456789"); // 提交事務(wù) session.getTransaction().commit(); } catch (Exception e) { // 發(fā)生異常,則回滾事務(wù) session.getTransaction().rollback(); System.out.println("修改User數(shù)據(jù)失?。?); e.printStackTrace(); } finally{ // 關(guān)閉 Session 對(duì)象 HibernateUtil.closeSession(); } }
控制臺(tái)輸出:
五月 09, 2023 12:00:16 上午 org.hibernate.dialect.Dialect INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect五月 09, 2023 12:00:17 上午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateServiceINFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_, user0_.password as password3_0_0_ from user user0_ where user0_.id=?Hibernate: update user set name=?, password=? where id=?
可以看到運(yùn)行前和運(yùn)行后,數(shù)據(jù)的變化,如圖:
刪除操作如果屏幕前的小伙伴是按照我的步驟一步一步跟下來(lái),那么你可能會(huì)遇到中文亂碼的問題,此時(shí)需要在 hibernate.cfg.xml 配置文件中修改 URL,加上兩個(gè)參數(shù)
useUnicode=true&characterEncoding=UTF-8
,如下:
jdbc:mysql://localhost:3306/demo_hibernate?useUnicode=true&characterEncoding=UTF-8
刪除操作需要先把數(shù)據(jù)查詢出來(lái),然后通過 Session 對(duì)象的 delete 方法將其刪除。代碼如下:
@Test public void delete() { // 獲取 Session 對(duì)象 Session session = HibernateUtil.getSession(); try { session.beginTransaction(); User user = session.get(User.class, new Integer("1")); // 刪除操作 session.delete(user); session.getTransaction().commit(); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("刪除User數(shù)據(jù)失敗!"); e.printStackTrace(); } finally{ // 關(guān)閉 Session 對(duì)象 HibernateUtil.closeSession(); } }
控制臺(tái)輸出:
五月 09, 2023 12:10:09 上午 org.hibernate.dialect.Dialect INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect五月 09, 2023 12:10:10 上午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateServiceINFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_, user0_.password as password3_0_0_ from user user0_ where user0_.id=?Hibernate: delete from user where id=?
關(guān)于 Hibernate 中對(duì)象的狀態(tài)在Hibernate中,對(duì)象的狀態(tài)有 4 種,分別為 Transient、Persistent、Detached、Removed,譯名就比較多,方便起見,我選擇 3 個(gè)字的譯名:
瞬時(shí)態(tài)(Transient):當(dāng)一個(gè)對(duì)象被實(shí)例化后,它處于瞬時(shí)態(tài),簡(jiǎn)單理解,就是new 操作之后
。瞬時(shí)態(tài)的對(duì)象沒有與之關(guān)聯(lián)的數(shù)據(jù)庫(kù)記錄,并且沒有被 Hibernate 的 Session 管理。當(dāng)將瞬時(shí)態(tài)的對(duì)象關(guān)聯(lián)到持久態(tài)對(duì)象或通過 Session 對(duì)象的 save
、persist
等方法進(jìn)行持久化操作后,該對(duì)象的狀態(tài)會(huì)發(fā)生變化,轉(zhuǎn)成持久態(tài)。持久態(tài)(Persistent):當(dāng)一個(gè)對(duì)象與 Hibernate 的 Session 關(guān)聯(lián)后,它就處于持久態(tài)。持久態(tài)的對(duì)象有與之對(duì)應(yīng)的數(shù)據(jù)庫(kù)記錄,并且被 Hibernate 的 Session 管理。對(duì)持久態(tài)對(duì)象的任何更改都會(huì)自動(dòng)同步到數(shù)據(jù)庫(kù)。持久態(tài)對(duì)象可以通過Session的 get
、load
等方法從數(shù)據(jù)庫(kù)中獲取,或者通過 save
、update
、persist
等方法進(jìn)行持久化操作。游離態(tài)(Detached):當(dāng)一個(gè)持久態(tài)對(duì)象與 Hibernate 的 Session 分離后,它處于游離態(tài)。游離態(tài)的對(duì)象仍然有與之對(duì)應(yīng)的數(shù)據(jù)庫(kù)記錄,但不再受 Hibernate 的 Session 管理。對(duì)游離態(tài)對(duì)象的更改不會(huì)自動(dòng)同步到數(shù)據(jù)庫(kù)。可以通過 Session 的 evict
、clear
等方法將持久態(tài)對(duì)象轉(zhuǎn)變?yōu)橛坞x態(tài)對(duì)象,或者通過 Session 的 merge
方法將游離態(tài)對(duì)象重新關(guān)聯(lián)到 Session 中。刪除態(tài)(Removed):當(dāng)一個(gè)持久態(tài)對(duì)象被從 Hibernate 的 Session中刪除后,它處于刪除態(tài)。刪除態(tài)的對(duì)象仍然有與之對(duì)應(yīng)的數(shù)據(jù)庫(kù)記錄,但即將被從數(shù)據(jù)庫(kù)中刪除。刪除態(tài)對(duì)象可以通過 Session 的delete
方法進(jìn)行刪除操作。Hibernate 通過跟蹤對(duì)象的狀態(tài)變化,實(shí)現(xiàn)了對(duì)象與數(shù)據(jù)庫(kù)的同步。在 Hibernate 的事務(wù)管理中,對(duì)象的狀態(tài)轉(zhuǎn)換是自動(dòng)進(jìn)行的,我們無(wú)需手動(dòng)操作,Hibernate 會(huì)根據(jù)對(duì)象的狀態(tài)進(jìn)行相應(yīng)的數(shù)據(jù)庫(kù)操作,保證對(duì)象與數(shù)據(jù)庫(kù)的一致性。
需要注意的是,Hibernate 的對(duì)象狀態(tài)與數(shù)據(jù)庫(kù)的操作并不是一一對(duì)應(yīng)的,Hibernate 提供了一系列的持久化方法和操作,我們可以根據(jù)具體的需求選擇合適的方法來(lái)進(jìn)行對(duì)象狀態(tài)的轉(zhuǎn)換和數(shù)據(jù)庫(kù)操作。對(duì)于復(fù)雜的業(yè)務(wù)邏輯和數(shù)據(jù)處理,需要仔細(xì)理解和管理對(duì)象的狀態(tài),以避免數(shù)據(jù)不一致的問題。
懶加載Hibernate 的懶加載(Lazy Loading)是一種延遲加載策略,它允許程序在需要訪問相關(guān)數(shù)據(jù)時(shí)才從數(shù)據(jù)庫(kù)中加載關(guān)聯(lián)對(duì)象的屬性或集合。
在 Hibernate 中,懶加載是通過使用代理對(duì)象來(lái)實(shí)現(xiàn)的。實(shí)際上,我們?cè)谘菔?Session 對(duì)象的 load()
方法時(shí),就是懶加載了,一開始返回的是代理對(duì)象,并沒有直接查詢數(shù)據(jù)庫(kù),而是直到該代理對(duì)象的屬性或方法被調(diào)用時(shí),Hibernate 會(huì)根據(jù)需要自動(dòng)執(zhí)行額外的數(shù)據(jù)庫(kù)查詢,從而延遲加載關(guān)聯(lián)的數(shù)據(jù)。
這就是懶加載,等到需要的時(shí)候才去加載。
懶加載的主要優(yōu)點(diǎn)是可以提高系統(tǒng)性能和減少不必要的數(shù)據(jù)庫(kù)查詢。如果一個(gè)對(duì)象關(guān)聯(lián)的屬性或集合在業(yè)務(wù)邏輯中很少被使用,懶加載可以避免不必要的數(shù)據(jù)庫(kù)訪問,減輕數(shù)據(jù)庫(kù)負(fù)載。
除了 load
方法實(shí)現(xiàn)的懶加載,我們還可以通過設(shè)置映射文件中的
標(biāo)簽的 lazy
屬性實(shí)現(xiàn)懶加載:
緩存緩存是一種臨時(shí)存儲(chǔ)數(shù)據(jù)的方式,將數(shù)據(jù)保存在更快速的存儲(chǔ)介質(zhì)(如內(nèi)存)中,以便將來(lái)能夠快速訪問和檢索。
Hibernate 提供了緩存的技術(shù),主要用于存儲(chǔ)實(shí)體對(duì)象以及查詢的結(jié)果集。緩存分為一級(jí)緩存(Session 緩存)和二級(jí)緩存(Session Factory 緩存)。
一級(jí)緩存一級(jí)緩存是與 Session 相關(guān)聯(lián)的緩存,它存儲(chǔ)了從數(shù)據(jù)庫(kù)中讀取的實(shí)體對(duì)象。在同一個(gè) Session 中,當(dāng)多次查詢相同的數(shù)據(jù)時(shí),Session 首先會(huì)根據(jù)對(duì)應(yīng)的持久化類和唯一性標(biāo)識(shí)(一般指的是ID)去緩存中查找是否存在該數(shù)據(jù)。如果存在,則直接從緩存中獲取,而不再訪問數(shù)據(jù)庫(kù);如果不存在,則繼續(xù)向二級(jí)緩存種查找。
一級(jí)緩存是默認(rèn)開啟的,可以提高讀取性能。
示例:
@Test public void testFirstLevelCache() { Session session = HibernateUtil.getSession(); try { System.out.println("第一次查詢:"); User user = session.get(User.class, new Integer("2")); System.out.println("用戶名:" + user.getName()); System.out.println("第二次查詢:"); User user2 = session.get(User.class, new Integer("2")); System.out.println("用戶名:" + user2.getName()); } catch (Exception e) { System.out.println("查詢User數(shù)據(jù)失??!"); e.printStackTrace(); } finally{ // 關(guān)閉 Session 對(duì)象 HibernateUtil.closeSession(); } }
控制臺(tái)輸出:
五月 09, 2023 9:35:31 下午 org.hibernate.dialect.Dialect INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect五月 09, 2023 9:35:32 下午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateServiceINFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]第一次查詢:Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_, user0_.password as password3_0_0_ from user user0_ where user0_.id=?用戶名:god23bin第二次查詢:用戶名:god23bin
可以看到,第二次查詢是沒有執(zhí)行 SQL 的,直接從一級(jí)緩存中獲取。
二級(jí)緩存二級(jí)緩存是在 SessionFactory 級(jí)別上的緩存,用于緩存多個(gè) Session 之間共享的數(shù)據(jù)。它可以減少對(duì)數(shù)據(jù)庫(kù)的訪問次數(shù),提高性能和擴(kuò)展性。二級(jí)緩存可以存儲(chǔ)實(shí)體對(duì)象、集合對(duì)象以及查詢結(jié)果集。
由于 Hibernate 本身并未提供二級(jí)緩存的具體實(shí)現(xiàn),所以需要借助其他緩存插件或者說策略來(lái)實(shí)現(xiàn)二級(jí)緩存。比如 Ehcache、Redis 等。
我們這里直接使用 Ehcache。
引入依賴項(xiàng) org.hibernate hibernate-ehcache 5.6.14.Final net.sf.ehcache ehcache 2.10.0
開啟二級(jí)緩存二級(jí)緩存默認(rèn)是關(guān)閉的,我們需要手動(dòng)開啟。在 hibernate.cfg.xml
中開啟二級(jí)緩存:
... true true org.hibernate.cache.ehcache.internal.SingletonEhcacheRegionFactory
創(chuàng)建緩存配置文件我們?cè)?/src/main/resources
目錄下創(chuàng)建緩存配置文件 ehcache.xml:
在持久化類的映射文件中指定緩存策略User.hbm.xml:
...
測(cè)試二級(jí)緩存:
@Test public void testSecondLevelCache() { Session session1 = HibernateUtil.getSession(); Session session2 = HibernateUtil.getSession(); try { System.out.println("第一個(gè) Session 去查詢數(shù)據(jù)并封裝成對(duì)象"); User user1 = session1.get(User.class, new Integer("2")); System.out.println("用戶名:" + user1.getName()); System.out.println("第二個(gè) Session 去查詢同一數(shù)據(jù)并封裝成對(duì)象"); User user2 = session2.get(User.class, new Integer("2")); System.out.println("用戶名:" + user1.getName()); } catch (Exception e) { System.out.println("查詢User數(shù)據(jù)失?。?); e.printStackTrace(); } finally{ // 關(guān)閉 Session 對(duì)象 HibernateUtil.closeSession(); } }
控制臺(tái)輸出:
五月 09, 2023 11:18:31 下午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateServiceINFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]第一個(gè) Session 去查詢數(shù)據(jù)并封裝成對(duì)象Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_, user0_.password as password3_0_0_ from user user0_ where user0_.id=?用戶名:god23bin第二個(gè) Session 去查詢同一數(shù)據(jù)并封裝成對(duì)象用戶名:god23bin
總結(jié)本篇文章主要講了基本的 CRUD 操作,都是通過 Session 去操作的,根據(jù)一個(gè)持久化類的類型以及一個(gè)唯一標(biāo)識(shí)進(jìn)行相關(guān)操作,然后講了 Hibernate 中的對(duì)象的狀態(tài),有 4 種,分別是瞬時(shí)、持久、游離、刪除。
接著說了 Hibernate 的懶加載,有利于降低數(shù)據(jù)庫(kù)的開銷,當(dāng)然緩存也是,除了加快我們的訪問速度,也降低了直接訪問數(shù)據(jù)庫(kù)的開銷,緩存就兩種,一級(jí)和二級(jí),一級(jí)默認(rèn)是開啟的,二級(jí)需要引入相關(guān)的依賴項(xiàng),然后進(jìn)行配置,開啟二級(jí)緩存,配置緩存策略。
這里附上整個(gè)項(xiàng)目的目錄結(jié)構(gòu),便于對(duì)照:
以上,就是本篇的內(nèi)容,這些都應(yīng)該掌握。咱們下期再見。
最后的最后希望各位屏幕前的靚仔靚女們
給個(gè)三連!你輕輕地點(diǎn)了個(gè)贊,那將在我的心里世界增添一顆明亮而耀眼的星!
咱們下期再見!
標(biāo)簽:
愛滋病的早期癥狀是什么感覺_愛滋病的早期癥狀是什么
河南安陽(yáng):中國(guó)文字博物館開展“國(guó)際博物館日”主題活動(dòng)
熱文:金建高鐵、甬舟鐵路、杭紹甬高速……“浙”些工程有新進(jìn)展
深圳試行無(wú)人機(jī)送外賣 無(wú)人機(jī)行業(yè)市場(chǎng)深度分析 天天日?qǐng)?bào)
天天熱消息:安徽財(cái)經(jīng)大學(xué)2023年自考畢業(yè)論文怎么報(bào)名,報(bào)名流程是怎樣的?
世界簡(jiǎn)訊:湖南航空首航七周年,目前全年運(yùn)營(yíng)航線63條,通航41個(gè)城市
當(dāng)前要聞:湖人利好!哈姆放話2米35長(zhǎng)臂男當(dāng)奇兵,球迷:約基奇轟45+15+12
國(guó)際物流業(yè)務(wù)員怎么找客戶_國(guó)際物流業(yè)務(wù)員怎樣找到自己的客戶|時(shí)訊
全球觀速訊丨高瀾股份:5月19日接受機(jī)構(gòu)調(diào)研,民生證券、東方阿爾法等多家機(jī)構(gòu)參與
舉信賴 敬真情 賴茅與世界羽聯(lián)再續(xù)合作情緣
焦點(diǎn)要聞:美聯(lián)儲(chǔ)6月加息概率降至15.7%
環(huán)球動(dòng)態(tài):1499元!暢享60 Pro即將發(fā)售
慶元旦演講稿3分鐘-慶元旦演講稿|每日精選
焦點(diǎn)信息:360路由器衛(wèi)士手機(jī)版安全下載_360路由衛(wèi)士
WE官博致謝前隊(duì)員:謝謝你們把WE帶到MSI決賽舞臺(tái)
六五環(huán)境日|濱州以督促改、以改促效,助力企業(yè)家成就夢(mèng)想 環(huán)球?qū)崟r(shí)
環(huán)球報(bào)道:項(xiàng)目實(shí)戰(zhàn)-重塑企業(yè)求職新場(chǎng)景
“賣點(diǎn)”變“槽點(diǎn)”,長(zhǎng)沙湘水郡中央空調(diào)成擺設(shè),業(yè)主吐槽:堪比“蒸桑拿”
環(huán)球關(guān)注:被辭退的艦長(zhǎng):希兒,敵人的陰謀(下)
每日信息:澤連斯基暗示烏克蘭東部城鎮(zhèn)巴赫穆特失守
057期李員外雙色球預(yù)測(cè)獎(jiǎng)號(hào):小復(fù)式9+3推薦 觀察
當(dāng)前短訊!銀翹解毒顆粒作用機(jī)制_銀翹解毒顆粒的作用
全球即時(shí)看!奇跡神戰(zhàn)什么職業(yè)厲害_奇跡戰(zhàn)神神賜等級(jí)列表
【環(huán)球快播報(bào)】1:0小勝主場(chǎng)大連人 河南隊(duì)艱難拿到聯(lián)賽首勝
當(dāng)前動(dòng)態(tài):蟲洞空間平臺(tái)_蟲洞空間