Java/Kotlin雙語革命性ORM框架Jimmer(一)——介紹與簡單使用

概覽

Jimmer是一個Java/Kotlin雙語框架

  • 包含一個革命性的ORM

  • 以此ORM為基礎打造了一套綜合性方案解決方案,包括

    • DTO語言

    • 更全面更強大的緩存機制,以及高度自動化的緩存一致性

    • 更強大客戶端文檔和代碼生成能力,包括Jimmer獨創的遠程異常

    • 快速創建GraphQL服務

    • 跨越微服務的遠程實體關聯

ORM部分

當前技術生態下,訪問關系型數據庫技術體系存在很大缺陷,請看下圖。
在這里插入圖片描述

1. 以JPA為代表的靜態語言ORM

優點

便捷,代碼安全(本身基于強類型語言,大部分代碼是安全的。如果結合QueryDSL使用,則可以保證所有代碼都是安全的)

缺點

缺乏靈活性

即使JPA從2.1開始支持EntityGraph,控制被查詢數據格式的靈活性仍然非常有限。該方案粒度仍然太粗,控制能力遠沒GraphQL這類技術的細膩。

保存對象時,細節行為受普通屬性的insertable、updateable和關聯屬性的cascade配置的控制,這類配置在實體類型中被硬編碼固化,被保存的數據結構的格式是固定的,沒有靈活性。

如果要發揮ORM的優勢,就必須查詢對象的大部分非關聯屬性 (少數@Basic(fetch = FetchType.Lazy)屬性除外,它們多為lob設計);如果只想查詢一部分屬性,就必須放棄對象查詢,轉而使用這些屬性的多列查詢,喪失ORM本該有的便捷性和核心價值。

3. 以為ActiveRecord (Ruby) 為代表的動態語言ORM

優點

基于動態語言的ORM,只需將動態語言對象結構的靈活性和ORM的實現結合起來,就能兼顧便捷和靈活。

缺點

動態語言雖然既便捷又靈活,但是代碼缺乏可維護性且不利于多人協同開發是眾所周知的缺點。

現代軟件往往是復雜的,需要團隊協作來完成,是否利于團隊成員之間協同,遠比個人對編程的認知重要。

這里,不想過多地討論動靜之爭,但是有一點需要指出:既然選擇了靜態語言Java/Kotlin,就應該以靜態語言的方式使用它, 而不能使用以jFinal為代表的將靜態語言當成動態語言用的方案,更不能在應用中頻繁地使用java.util.Map來代替數據對象。 這類做法違背了選擇Java/Kotlin的初衷,如果一定要怎么做,為什么不直接選動態語言呢?

4. 以MyBatis為代表的輕量級SQL Builder/Mapper

優點

直接編寫SQL,隨意且靈活;本身是強類型框架,具有代碼安全性 (MyBatis生態也有強類型SQL DSL擴展,可以解決原生SQL字符串導致的代碼不安全問題)

缺點

便捷性的嚴重缺失,重復勞動量極大。

MyBatis沒有統一實體的概念,而是面對具體業務場景DTO,實現ResultSet和這些DTO的映射。由于業務場景多,各DTO類型之間相似卻不同,冗余度很高,導致重復勞動量極高。

除了以孤單對象為載體的CRUD外,對多個對象彼此關聯而成的復雜數據結構的支持較弱,缺乏必要抽象,導致太多繁重的低級任務被推卸給開發人員 (不少開發人員長期被這類繁重的任務所累,但自己一直沒察覺)。

原生SQL真的是最好方案嗎?
這個派別最引以為豪的觀點是:“直接書寫SQL會帶來更直接的控制力,這種直接控制力優于任何ORM”。在這個領域長期的技術停滯中,不少開發人員對此深信不疑。

根本原因

上文中,我們闡述了關系型數據庫領域的三種常見方案,但無論如何選擇,我們都無法兼顧便捷性、靈活性和代碼安全性。為什么會導致這樣呢?

就JVM生態而言,POJO是導致這個問題的根本原因。

POJO*(也可以叫結構體)*缺乏必要的靈活性和表達力,卻幾乎被所有的JVM框架作為數據模型和核心,嚴重限制了JVM生態的技術創新。

因此,在Jimmer中,ORM實體對象并非POJO。而是另外一種獨特的萬能數據對象*(后文會介紹)*,這種獨特的實體對象撐起了Jimmer所有上層重大的變革,是整個框架的基石。

事實上,Jimmer實體對象不僅可以應用在ORM領域,它幾乎可以用在任何以結構化數據維護為目的的場景,并提升各種技術棧的表達力。

目前,Jimmer實體僅在關系型數據庫訪問領域發揮出作用,只是因為精力不夠所致。

完整的功能

在本文開頭我們提到了,革命性的ORM只是Jimmer的一部分,Jimmer實際的能力范圍早已超越了一個ORM。

現在,我們給出Jimmer的功能示意圖,并逐個講解
在這里插入圖片描述

Business Model

在信息類系統中,存在兩種對象。

實體:實體對象是全局統一的,對象之間的存在豐富彼此關聯。

實體對象往往和數據庫非常接近,具備極高的穩定性。

DTO:針對特定業務的輸入/輸出對象,通常是從全局實體關系網上撕下來的一個局部碎片,該碎片的大小和形狀非常靈活。

DTO類型數量龐大,每一個業務接口對DTO對象的格式都有獨特的需求,彼此可能相似但又不同,具備明顯的。而且易受到需求變化的影響,不穩定。

Entity類型是全局統一數據存儲模型,不易被需求變更影響,相對穩定,被視為高價值類型。

DTO類型作為每個業務輸入/輸出,相對隨意,容易因需求變動而不穩定,被視為低價值類型。

Jimmer主張開發人員把精力集中在高價值的實體模式的設計上;對于低價值的DTO類型,有的時候并不需要,有的時候需要。
即使需要,也可以用極其廉價的方式自動生成。因此,基于Jimmer構建的項目具備優秀的抗需求變動的能力。

Jimmer Entity

Jimmer實體定義和JPA實體很接近。

之前討論過,Jimmer實體并非POJO,所以,被聲明為interface,而非class。

那么,誰負責實現此接口呢?是上圖中的Jimmer Precompiler (對于Java而言,就是APT; 對于Kotlin而言,就是KSP)

Jimmer實體支持兩個重要特征,動態性和不可變性

動態性

Jimmer對象在靜態語言和動態語言之間尋求最佳平衡,把二者的優點結合起來:

  • 靜態語言數據對象具有高性能、拼寫安全、類型安全、甚至空安全*(如果使用Kotlin的話)*的優點,Jimmer實體吸收了這些優點。
  • 動態語言數據對象具有高度的靈活性,Jimmer實體吸收了這個優點,每個屬性都可以缺失*(但是不能如同動態語言一樣增加屬性,因為這必然會破壞靜態語言的特性,Jimmer也不需要此能力)*

對Jimmer而言,對象缺少某個屬性 (其值未知) 和 對象的某個屬性為null (其值已知) 是完全不同的兩回事。

這種平衡設計,可以在享受靜態語言好處的同時,為數據結構賦予。

這種絕對的靈活性,既可用于表達查詢業務的輸出格式,也可用于表達保存業務的輸入格式。

這導致Jimmer擁有了嶄新的定位:一個為任意形狀數據結構設計的ORM。其所有功能都是為了操作任意形狀的數據結構,而非一個個簡單的實體對象。

不可變性

Jimmer對象是不可變對象。不可變對象的好處是多方面的

Jimmer選擇不可變對象是為了讓數據結構絕不包含循環引用。

這可以保證由Jimmer實體及彼此關聯組合而成的數據結構一定能夠被直接Jackson序列化,并不需要使用詭異的序列化技巧為JSON植入任何特殊的額外信息,任何編程語言都可以輕松理解。

然而,不可變對象也存在缺點。比如,現有一個很深的數據結構,那么基于它按照一些修改的愿望創建出新的數據結構會很困難,難度隨著深度的變大急劇增加。

ORM和很深的數據結構打交道,而Java的record和Kotlin的data class不適合處理很深數據結構。

既對Java和Kotlin進行雙語支持,又善于基于現有深層次數據結構按照一些修改的愿望創建出新的不可變數據結構的方案,目前的JVM生態沒有。

幸運的是,JavaScript/TypeScript領域存在一個足夠強大的方案: immer,可以完美解決這個問題。該方案工作方式如下

基于現有不可變數據結構開啟一個臨時作用域。

在這個作用域內,開發人員可得到一個draft數據結構,該數據結構的形狀和初始值和原數據結構完全一致,且可以被隨意修改,包括修改任意深的子對象。

作用域結束后,draft數據結構會利用收集到的修改行為創建另外一個新的數據結構。其中,未被修改的局部會被優化處理,復用以前的舊對象。

Immer完美結合了不可變對象和可變對象的優點,代碼簡單、功能強大、性能卓越。因此,Jimmer選擇為JVM生態移植了immer,項目名稱也是對其致敬。

Generated DTO Type

前文談到,Jimmer實體在靜態語言數據對象和動態語言數據對象之間尋找最佳平衡,其中動態性帶來了極大的靈活性,并以此決定了整個框架的定位。

Jimmer對象允許某些屬性缺失,對象缺少某個屬性 (其值未知) 和 對象的某個屬性為null (其值已知) 是完全不同的兩回事。

  • 對于Jackson序列化而言,缺失的屬性會被自動忽略,就如同我們之前展示的那樣。

    如果服務端自己并不使用查詢得到的實體對象,而是直接寫入到Http Response中。對于這種情況,無需DTO,直接使用實體對象很方便。

  • 如果直接用Java/Kotlin代碼訪問不存在的屬性,會導致異常。

這并非由Jimmer制造的新問題,而是一個在靜態語言ORM生態中早已存在和被接受的問題。然而,不可否認這的確對靜態語言的安全性形成了破壞。

如果要追求100%的靜態語言安全性,使用DTO對象是唯一的方法。然而,目前JVM生態的DTO映射技術存在很大缺陷。

  • 要么顯式地映射屬性*(例如純手工映射和轉化)*,這種做法工作量巨大,枯燥且容易出錯。
  • 要么隱式地映射屬性*(例如采用BeanUtils技術)*,這種做法會引入新的不安全問題,即,無法在編譯發現的問題。

即使你使用強大的mapstruct,你所能做的也只是在這兩個極端之間作出選擇而已。

因此,Jimmer提供了DTO語言,用戶使用該語言編寫非常簡單的代碼,編譯項目即可自動生成各種豐富的DTO類型定義。

DTO語言的設計目的,在于

讓生成DTO類型的過程足夠簡單,從而讓DTO類型足夠廉價。

100%符合靜態語言安全性,在編譯時發現所有問題并報錯。

理論概念先到這里

簡單使用

我們做一個簡單的查詢demo,創建Springboot項目

引入依賴

<dependency><groupId>org.babyfish.jimmer</groupId><artifactId>jimmer-spring-boot-starter</artifactId><version>0.8.51</version></dependency>

編寫Model

用戶

@Entity
@Table(name = "User")
public interface User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)int id();String name();@NullableInteger age();@OneToMany(mappedBy = "user")List<UserDetail> details();
}

用戶詳情,一對多

@Entity
@Table(name = "user_detail")
public interface UserDetail {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)int id();@Key // 自己的核心數據自然就是第二個業務鍵String detail();@Key // 父級自然是一個業務鍵@OnDissociate(DissociateAction.DELETE) // 如果脫鉤了,就把自身刪除@ManyToOne@JoinColumn(name = "user_id",foreignKeyType = ForeignKeyType.FAKE)@NullableUser user();@IdView("user")Integer userId();}

配置數據庫鏈接

applicantion.yml

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://myhost:3306/my_jimmerusername: rootpassword: rootjimmer:dialect: org.babyfish.jimmer.sql.dialect.MySqlDialectshow-sql: onpretty-sql: truedatabase-validation:schema: my_jimmer

構建

Maven build

查詢

@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate JSqlClient sqlClient;@RequestMapping("/user")public List<User> find(@RequestBody UserSpecification specification){UserTable userTable = UserTable.$;return sqlClient.createQuery(userTable).select(userTable).execute();}
}

超級查詢

使用specification,可以提供靈活的復雜查詢

定義dto

export com.example.myjimmer.entity.User-> package com.example.myjimmer.dto/*UserView {#allScalars(User)details {#allScalars(UserDetail)}
}*/specification UserSpecification {eq(name) as namelike(name) as likename
}

構建

Maven build

使用specification查詢

@RestController
@RequestMapping("/test")
public class TestController {@Autowiredprivate JSqlClient sqlClient;@RequestMapping("/user")public List<User> find(@RequestBody UserSpecification specification){UserTable userTable = UserTable.$;return sqlClient.createQuery(userTable).where(specification).select(userTable).execute();}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/69268.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/69268.shtml
英文地址,請注明出處:http://en.pswp.cn/web/69268.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

openAI官方prompt技巧(一)

1. 使用最新的模型 2. 將指令放在提示詞的開頭&#xff0c;并使用 ### 或 """ 來分隔指令和上下文&#xff0c;例如 錯誤示范? 將下面的文本總結為一個要點列表&#xff0c;列出最重要的內容。 Summarize the text below as a bullet point list of the most…

通過制作docker鏡像的方式在阿里云部署前端后臺服務

前端Dockerfile文件的內容&#xff1a; FROM nginx:版本&#xff0c;如果不指定&#xff0c;默認是latest COPY dist/ /usr/share/nginx/html/dist COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 端口 前端sh腳本文件內容&#xff1a; appName項目名 tar -xvf dist.tar …

Github 2025-02-04 Python開源項目日報 Top10

根據Github Trendings的統計,今日(2025-02-04統計)共有10個項目上榜。根據開發語言中項目的數量,匯總情況如下: 開發語言項目數量Python項目10TypeScript項目1Python中的算法實現集合 創建周期:2831 天開發語言:Python協議類型:MIT LicenseStar數量:178357 個Fork數量:…

yolov11模型在Android設備上運行【踩坑記錄】

0) 參考資料: https://github.com/Tencent/ncnn?tabreadme-ov-file https://github.com/pnnx/pnnx https://github.com/nihui/ncnn-android-yolov5 https://github.com/Tencent/ncnn?tabreadme-ov-file 1) &#xff1a;將xxx.pt模型轉化成 xxx.onnx ONNX&#xff08;Ope…

快速上手——.net封裝使用DeekSeek-V3 模型

??歡迎點贊 :?? 收藏 ?留言 ?? 如有錯誤敬請指正,賜人玫瑰,手留余香!??本文作者:由webmote 原創??作者格言:新的征程,用愛發電,去丈量人心,是否能達到人機合一?開工大吉 新的一年就這么水靈靈的開始了,在這里,祝各位讀者新春快樂,萬事如意! 新年伊…

2025藍橋杯JAVA編程題練習Day2

1.大衣構造字符串 問題描述 已知對于一個由小寫字母構成的字符串&#xff0c;每次操作可以選擇一個索引&#xff0c;將該索引處的字符用三個相同的字符副本替換。 現有一長度為 NN 的字符串 UU&#xff0c;請幫助大衣構造一個最小長度的字符串 SS&#xff0c;使得經過任意次…

【WebLogic】Oracle發布WebLogic 14c最新版本-14.1.2.0

根據Oracle官方產品經理的博客&#xff0c;Oracle于2024年12月20日正式對外發布了WebLogic 14c的第二個正式版本&#xff0c;版本號為 14.1.2.0.0 &#xff0c;目前官方已開放客戶端下載。該版本除繼續支持 Jakarta EE 8 版本外&#xff0c;還增加了對 Java SE 17&#xff08;J…

Spider 數據集上實現nlp2sql訓練任務

NLP2SQL&#xff08;自然語言處理到 SQL 查詢的轉換&#xff09;是一個重要的自然語言處理&#xff08;NLP&#xff09;任務&#xff0c;其目標是將用戶的自然語言問題轉換為相應的 SQL 查詢。這一任務在許多場景下具有廣泛的應用&#xff0c;尤其是在與數據庫交互的場景中&…

IDEA+DeepSeek讓Java開發起飛

1.獲取DeepSeek秘鑰 登錄DeepSeek官網 : https://www.deepseek.com/ 進入API開放平臺&#xff0c;第一次需要注冊一個賬號 進去之后需要創建一個API KEY&#xff0c;然后把APIkey記錄保存下來 接著我們獲取DeepSeek的API對話接口地址&#xff0c;點擊左邊的&#xff1a;接口…

k8s常見面試題2

k8s常見面試題2 安全與權限RBAC配置如何保護 Kubernetes 集群的 API Server&#xff1f;如何管理集群中的敏感信息&#xff08;如密碼、密鑰&#xff09;&#xff1f;如何限制容器的權限&#xff08;如使用 SecurityContext&#xff09;&#xff1f;如何防止容器逃逸&#xff0…

flutter安卓打包簽名

flutter安卓打包簽名 1.創建簽名文件 keytool -genkeypair -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-aliaskeytool 是一個用于管理密鑰和證書的命令行工具&#xff0c;通常與 Java 開發工具包 (JDK) 一起使用。my-release-…

React - jsx 語法

在 React 中&#xff0c;JSX&#xff08;JavaScript XML&#xff09;是一種語法擴展&#xff0c;它允許開發者在 JavaScript 代碼中使用類似 HTML 的語法。JSX 提升了代碼的可讀性和可維護性&#xff0c;使得編寫和構建用戶界面更加直觀。它被廣泛應用于 React 組件的定義。 一…

intra-mart實現簡易登錄頁面筆記

一、前言 最近在學習intra-mart框架&#xff0c;在此總結下筆記。 intra-mart是一個前后端不分離的框架&#xff0c;開發時主要用的就是xml、html、js這幾個文件&#xff1b; xml文件當做配置文件&#xff0c;html當做前端頁面文件&#xff0c;js當做后端文件&#xff08;js里…

Linux+Docer 容器化部署之 Shell 語法入門篇 【Shell 替代】

&#x1f380;&#x1f380;Shell語法入門篇 系列篇 &#x1f380;&#x1f380; LinuxDocer 容器化部署之 Shell 語法入門篇 【準備階段】LinuxDocer 容器化部署之 Shell 語法入門篇 【Shell變量】LinuxDocer 容器化部署之 Shell 語法入門篇 【Shell數組與函數】LinuxDocer 容…

Intellij IDEA如何查看當前文件的類

快捷鍵&#xff1a;CtrlF12&#xff0c;我個人感覺記快捷鍵很麻煩&#xff0c;知道具體的位置更簡單&#xff0c;如果忘了快捷鍵&#xff08;KeyMap&#xff09;看一下就記起來了&#xff0c;不需要再Google or Baidu or GPT啥的&#xff0c;位置&#xff1a;Navigate > Fi…

C++----繼承

一、繼承的基本概念 本質&#xff1a;代碼復用類關系建模&#xff08;是多態的基礎&#xff09; class Person { /*...*/ }; class Student : public Person { /*...*/ }; // public繼承 派生類繼承基類成員&#xff08;數據方法&#xff09;&#xff0c;可以通過監視窗口檢…

已驗證正常,Java輸入字符串生成PDF文件

Java輸入字符串生成PDF文件過程&#xff1a; 在Java開發中&#xff0c;如何將字符串轉換為 PDF 是一個常見的需求。網上找了很多例子都無法生成&#xff0c;經過多次嘗試&#xff0c;終于實現了&#xff0c;特此記錄一下。 1、引入pom.xml 添加所需的依賴 <dependency>&…

Mac M1 Comfyui 使用MMAudio遇到的問題解決?

問題1: AssertionError: Torch not compiled with CUDA enabled&#xff1f; 解決辦法&#xff1a;修改代碼以 CPU 運行 第一步&#xff1a;找到 /ComfyUI/custom_nodes/ComfyUI-MMAudio/mmaudio/ext/autoencoder/vae.py文件中的下面這兩行代碼 self.data_mean nn.Buffer(t…

從 .NET Framework 升級到 .NET 8 后 SignalR 問題處理與解決方案

隨著 .NET Framework 向 .NET 8 的遷移&#xff0c;許多開發者在使用 SignalR 時遇到了一些前后端連接、配置、調用等方面的問題。尤其是在處理 SignalR 實時通信功能時&#xff0c;升級后的一些兼容性問題可能導致應用程序無法正常工作。本文將介紹在從 .NET Framework 升級到…

2025.2.5——五、[網鼎杯 2020 青龍組]AreUSerialz 代碼審計|反序列化

題目來源&#xff1a;BUUCTF [網鼎杯 2020 青龍組]AreUSerialz 目錄 一、打開靶機&#xff0c;整理信息 二、解題思路 step 1&#xff1a;代碼審計 step 2&#xff1a;開始解題 突破protected訪問修飾符限制 三、小結 一、打開靶機&#xff0c;整理信息 直接得到一串ph…