Hibernate 差點毀了我的職業生涯
已發表: 2022-03-11想像一下,您是一名 Java 開發人員,並且您即將開始您的下一個大項目。 您需要做出在項目的其餘部分中將與您保持一致的基本決策。 您想為靈活的數據模型選擇最佳的面向對象抽象,因為您不想處理簡單的 SQL。 您希望支持各種數據,理想情況下,支持各種數據庫。
顯而易見的答案是只使用Hibernate ,對嗎? 90% 的 Java 開發人員會同意你的觀點,但這是否是正確的決定?
讓我們看看如果僅僅因為它是公認的標準而盲目使用Hibernate會出現什麼問題。
考慮一下 Java 開發人員 Monica。 Monica 最近被提升為架構師,現在負責為她公司的新產品佈置技術堆棧。 她知道在 Java 世界中只有一種處理數據庫通信的好工具: Hibernate 。 Hibernate是一個眾所周知且受支持的 JPA 標準。 但是,在開始項目之前檢查一些事情總是一個好主意。 幸運的是,她的同事 Ben 認識合適的人。
休眠聽起來像一顆銀彈
本- 你好莫妮卡,我想介紹約翰。 他是Hibernate專家,他會幫助你。
莫妮卡- 嘿約翰,很高興你有時間陪我。 所以,我們正在構建我們的下一件大事,你知道的。 我們正計劃成為下一個 Facebook 或 Google。 忙碌的日子。 這將是巨大的。 絕對精彩! 每個人都很興奮! 我已經被提升為架構師的角色,所以現在我必須選擇我們將使用的堆棧。 唯一缺少的部分是堅持……
約翰-冬眠!
莫妮卡——是的! 確切地! 正是我的想法! 對我們來說,這似乎是一個完美的匹配和真正的交易。 針對真正企業問題的真正企業解決方案,經市場證明且歷史悠久。 我聽到了很多關於它的積極經驗。 但是,我對我們的一位隊友有意見; 他完全反對。 他對數據庫非常了解,他害怕在我們的應用程序和數據庫之間添加另一層。 他非常聰明,我需要一些非常好的論據來說服他這是一個很好的決定。 你能幫我解決這個問題嗎?
約翰——當然! 我會很高興的。 Hibernate確實是一個出色的工具。 它廣泛用於大型、真正的企業解決方案,如銀行。 你不會錯的。 考慮持久性:選擇Hibernate 。 如果您使用 Java 編寫,這絕對是正確的選擇,而且您還有其他語言的端口。 看看有多少職位描述需要它!
莫妮卡——我完全同意! 我對此也有同樣的感受。 在之前的項目中,我們主要通過普通的舊 JDBC 使用 SQL。 荒謬的! 我知道! 但是,事情是這樣的:我們團隊中有非常聰明的 SQL 人員,當他們看到Hibernate生成的 SQL 時,他們很緊張。 它看起來醜陋且難以閱讀。 這會是未來的問題嗎?
約翰- 看。 DBA 人有不同的看法。 他們害怕Hibernate ,因為它似乎取代了他們在項目中的角色。 此外,數據庫具有內置的查詢優化器,因此您無需擔心這些查詢的實際外觀。 數據庫將為您優化它。 這都是關於快速開發的,這是 SQL 做不到的。
莫妮卡——真的嗎?! 不再處理 SQL? 驚人的! 上次 DBA 花了數週時間嘗試優化某些查詢。 週! 哦,告訴你這個我很尷尬,但你知道我們使用的是……存儲過程(笑)。 哦,真是一團糟。 你能相信這個項目還在使用它嗎? 我為外面的人感到非常抱歉。 他們仍然必須一遍又一遍地編寫這個乏味的代碼。 我想知道它是否仍然是 Java 或 SQL 項目?
John - 這正是面向對象方法和關係方法之間的區別。 這就是所謂的面向對象的阻抗失配。 Hibernate可以彌補這一差距。 開發人員可以專注於構建業務邏輯。 推送功能使利益相關者和整個管理層感到高興。 做最重要的事情:做生意! 許多樣板代碼將消失,您將在邏輯和數據之間建立一種神奇的、看不見的但可靠的連接。
莫妮卡——相互合作。 充分協同。 就像數據庫從一開始就是語言的一部分一樣。 我很高興能成為這種信仰技術飛躍的領導者。 這就像軟件跋涉中的翹曲速度。
約翰- 是的! 你明白了!
莫妮卡- 哦,天哪,我太興奮了! 謝謝你,約翰! 我準備好了!
不靈活的解決方案帶來的痛苦
Monica - Hey John,還記得我們去年談到的那個項目嗎?
約翰——當然。 怎麼樣了?
莫妮卡——我們很快就要生產了。 一切都很好,但出現了一些問題。
約翰- 當然,打我。
Monica - 好吧,我們不能再從頭開始生成我們的數據庫模式。 在不丟失數據的情況下支持架構更改的最佳方式是什麼?
John - 首先, Hibernate不打算用作生產遷移工具。 使用 FlywayDB 或 Liquibase 之類的東西。 這很簡單。 您編寫遷移腳本,然後更新實體模型以及Hibernate映射,使其與實際數據庫結構保持同步。
莫妮卡——嗯,我明白了。 我們在之前的項目中只使用了普通的 SQL 遷移。
約翰- 那也很好。 只要您保持實體模型和模式同步,就可以按照您的喜好進行操作。
莫妮卡——我明白了。 還有一件事。 我們一直在為懶惰/急切的獲取問題而苦苦掙扎。 有一次,我們決定急切地做所有事情,但這似乎不是最理想的,此外,有時由於沒有會話或類似的原因,無法訪問某些字段。 這正常嗎?
John - 您需要了解更多有關Hibernate的信息。 從數據庫映射並不簡單。 基本上,有多種方法可以做到這一點。 您只需要選擇一種適合您的方式。 延遲獲取使您能夠按需加載這些對象,但您需要在活動會話中進行操作。
Monica - 我們仍在為最終部署使用哪個數據庫引擎而苦苦掙扎。 我認為Hibernate是可移植的,但我們有一些使用 MS SQL 魔法的本機查詢,我們實際上希望在生產中使用 MySQL。
John - 只要您使用分離的標准或 HQL, Hibernate就會為您提供靈活性; 任何本機查詢只會將您的解決方案綁定到數據庫。
Monica - 看來我們必須堅持使用 MS SQL。 最後一個問題:我的隊友說HQL中沒有“limit”關鍵字。 我以為他在開玩笑,但我也找不到。 對不起這個愚蠢的問題......
John - 事實上,HQL 中沒有“限制”關鍵字。 您可以通過查詢對象來控制它,因為它是特定於數據庫供應商的。
Monica - 所有其他元素都在 HQL 中,這似乎很奇怪。 沒關係。 謝謝你的時間!
我們現在再次在 SQL 中一起破解解決方案
Monica - John,一開始我們不打算處理 SQL,但現在看來我們必須處理。 我們的需求在增長,似乎沒有辦法繞過它。 感覺不對,但我們已經開始每天再次使用 SQL。

約翰——嗯,沒錯。 您不必在一開始就專注於數據庫。 但是,隨著項目的發展,最好使用 SQL 並進行性能優化。
Monica - 有時我們會花費數天時間尋找錯誤。 似乎我們必須分析Hibernate生成的 SQL,因為我們不知道為什麼它沒有按預期工作並且會產生意想不到的結果。 我們遇到了一些在Hibernate錯誤跟踪器中眾所周知的問題。 此外,很難在保持實體模型同步的同時編寫正確的遷移。 這很耗時,因為我們需要了解很多有關Hibernate內部結構的知識並預測它的工作原理。
約翰- 總有一條學習曲線。 你不必寫太多,但你需要知道它是如何工作的。
Monica - 使用更大的數據集也很煩人。 最近,我們對數據庫進行了大規模導入,而且速度非常緩慢。 然後我們發現我們必須清除會話以使其更快。 即便如此,它仍然慢得多,所以我們決定將其重寫為普通的 SQL 語句。 有趣的是,編寫純 SQL 實際上是最快的方法,所以我們決定將其作為最後的選擇。
John - Import 不是一個面向對象的過程。 Hibernate專注於面向對象的設計。 請記住,您始終可以使用本機查詢。
Monica - 你能幫我理解Hibernate緩存是如何工作的嗎? 我只是不明白。 有一些一級/二級緩存。 這是怎麼回事?
約翰——當然。 它是持久數據的所謂事務級緩存。 可以逐個類和逐個集合地配置集群或 JVM 級緩存。 您甚至可以插入集群緩存。 但請記住,緩存不知道其他應用程序對持久存儲所做的任何更改。 但是,它們可以配置為定期刪除過期的緩存數據。
莫妮卡- 對不起,我覺得我今天過得很糟糕。 你能再解釋一下嗎?
約翰——當然。 每當您將對像傳遞給save
、 update
、 saveOrUpdate
或通過load
、 get
、 list
、 iterate
或scroll
檢索時,該對像都會添加到會話的內部緩存中。 您還可以從一級緩存中刪除對象及其集合。
莫妮卡——呃……
John - 此外,您可以控制緩存模式。 您可以使用normal
模式讀取和寫入項目到二級緩存。 使用get
模式從第二級讀取,但不能回寫。 使用put
,它與get
相同,但您不能從第二級讀取。 您還可以使用refresh
模式,該模式將寫入二級緩存,但不從二級緩存中讀取,並繞過use minimal puts
屬性,強制刷新從數據庫讀取的所有項目的二級緩存。
莫妮卡——我明白了。 好的。 讓我想想這個。 哦,時間不早了,我得走了。 謝謝你的時間!
約翰-不客氣!
放棄休眠
Monica - John,我以為我們正在進入一個軟件開發的新時代。 我以為我們在做光年的跳躍。 但是,四年後,我們似乎仍在處理所有相同的問題,只是從不同的角度。 我必須學習Hibernate架構、配置、日誌記錄、命名策略、元組器、實體名稱解析器、增強的標識符生成器、標識符生成器優化、聯合子類、XDoclet 標記、與索引集合的雙向關聯、三元關聯、idbag、將隱式多態性與其他繼承映射、在兩個不同的數據存儲之間複製對象、分離對象和自動版本控制、連接釋放模式、無狀態會話接口、集合持久性分類、緩存級別、惰性或急切獲取等等。 即使我所知道的一切,我們似乎都失敗了。 這是一場軟件慘敗! 最終失敗! 災難! 世界末日!
約翰- 等等! 發生了什麼?
莫妮卡——我們走到了死胡同。 我們的應用程序性能慢得離譜! 要獲得報告,我們必須等待兩天! 兩天時間為客戶實際生成儀表板。 這意味著我們每天都必須增加我們的計算尾部,而我們的儀表板變得越來越過時。 我們的 DBA 專家已經工作了兩個月來優化一些查詢,而我們的數據庫結構卻是一團糟。 有開發人員支持他,但問題是 DBA 正在思考 SQL,開發人員花費數天時間試圖將其轉換為獨立的標准或 HQL 格式。 我們正在嘗試盡可能多地使用原生 SQL,因為目前性能至關重要。 無論如何,我們不能做太多,因為數據庫模式似乎是錯誤的。 從面向對象的角度來看,這感覺是對的,但從關係的角度來看,這似乎很荒謬。 我在問自己:這是怎麼發生的? 開發人員告訴我們改變實體結構將是一項巨大的工作,所以我們負擔不起。 我記得在之前的項目中它是一團糟,但我們從未在如此關鍵的時刻結束。 我們能夠編寫一個完全不同的應用程序來處理數據。 現在,修改這些生成的表是有風險的,因為很難確保實體模型始終正常運行。 這甚至還不是最糟糕的部分! 為了提高性能,我們不僅要解決數據庫問題,還要解決數據庫和應用程序之間的整個層的問題。 這是壓倒性的! 我們有這些新人,你知道的,顧問。 他們試圖提取數據,將其放入其他存儲中,然後從外部執行計算。 這一切都花費了太多時間!
約翰——我不知道該說什麼。
莫妮卡——你看約翰; 我不想怪你。 我選擇Hibernate來解決所有這些問題,但現在我知道它不是靈丹妙藥。 傷害已經造成,而且是不可逆轉的。 實際上,我想問你一件事:在我職業生涯的最後四年裡,我一直在處理Hibernate的東西。 我現在的公司似乎沒有未來。 你能幫助我嗎?
那麼吸取的教訓是什麼?
約翰- 嘿,彼得,讓我介紹一下莫妮卡。
彼得- 嘿,莫妮卡! 我們正在構建我們新的下一件大事,你知道。 這將是巨大的! 我們想像優步一樣! 你知道也許如何堅持...
莫妮卡- 不是休眠!
包起來
Monica 是Hibernate專家。 然而,在這種情況下, Hibernate是一個錯誤的決定。 當她發現自己的解決方案變成了比原來更大的問題時,這就是對整個項目的最大威脅。
數據是應用程序的中心目的,無論喜歡與否,都會影響整個架構。 正如我們從這個故事中了解到的那樣,不要僅僅因為您的 Java 應用程序正在使用數據庫或因為社交證明而使用Hibernate 。 選擇一個包含靈活性的解決方案。 健壯的 JDBC 包裝器有很多選項,例如 JdbcTemplate 或 Fluent JDBC Wrapper。 或者,還有其他強大的解決方案,例如 jOOQ。