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();}
}
相关文章:

Java/Kotlin双语革命性ORM框架Jimmer(一)——介绍与简单使用
概览 Jimmer是一个Java/Kotlin双语框架 包含一个革命性的ORM 以此ORM为基础打造了一套综合性方案解决方案,包括 DTO语言 更全面更强大的缓存机制,以及高度自动化的缓存一致性 更强大客户端文档和代码生成能力,包括Jimmer独创的远程异常 …...

番外02:前端八股文面试题-CSS篇
一:CSS基础 1:CSS选择器及其优先级 2:display的属性值及其作用 属性值作用none元素不显示,并且会从文档流中移除block块类型,默认元素为父元素宽度,可设置宽高,换行显示inline行内元素类型&a…...

Redis Copilot:基于Redis为AI打造的副驾工具
我们最近发布了Redis Copilot,以帮助开发者更快地使用Redis构建应用。我们的使命是使应用程序快速运行,并简化构建过程。为此,Redis Copilot作为您的AI助手,能够让您更迅速地完成与Redis相关的任务。您今天就可以在Redis Insight中…...

JavaScript遍历对象的7种方式
注:纯手打,如有错误欢迎评论区交流! 转载请注明出处:https://blog.csdn.net/testleaf/article/details/145523427 编写此文是为了更好地学习前端知识,如果损害了有关人的利益,请联系删除! 本文章…...

如何避免NACK重传风暴
策略 1,10 次 NACK 模块对同一包号的最大请求次数,超过这个最大次数限制,会把该包号移出 nack_list,放弃对该包的重传请求。 策略 2,20 毫秒 NACK 模块每隔 20 毫秒批量处理 nack_list,获取一批请求包号…...

并发工具CountDownLatch、CyclicBarrier、Semaphore
文章目录 学习链接CountDownLatchCountDownLatch类的作用类的主要方法介绍图解await和countDown方法两个典型用法注意点总结示例CountDownLatchDemo1CountDownLatchDemo2CountDownLatchDemo1And2 CyclicBarrierCyclicBarrier循环栅栏CyclicBarrier和CountDownLatch的区别示例Cy…...

十二. Redis 集群操作配置(超详细配图,配截图详细说明)
十二. Redis 集群操作配置(超详细配图,配截图详细说明) 文章目录 十二. Redis 集群操作配置(超详细配图,配截图详细说明)1. 为什么需要集群-高可用性2. 集群概述(及其搭建)3. Redis 集群的使用4. Redis 集群故障恢复5. Redis 集群的 Jedis 开发(使用Java…...

网络工程师 (26)TCP/IP体系结构
一、层次 四层: 网络接口层:TCP/IP协议的最底层,负责网络层与硬件设备间的联系。该层协议非常多,包括逻辑链路和媒体访问控制,负责与物理传输的连接媒介打交道,主要功能是接收数据报,并把接收到…...

TensorFlow域对抗训练DANN神经网络分析MNIST与Blobs数据集梯度反转层提升目标域适应能力可视化...
全文链接:https://tecdat.cn/?p39656 本文围绕基于TensorFlow实现的神经网络对抗训练域适应方法展开研究。详细介绍了梯度反转层的原理与实现,通过MNIST和Blobs等数据集进行实验,对比了不同训练方式(仅源域训练、域对抗训练等&am…...

保姆级教程--DeepSeek部署
以DeepSeek-R1或其他类似模型为例,涵盖环境配置、代码部署和运行测试的全流程: 准备工作 1. 注册 Cloud Studio - 访问 [Cloud Studio 官网](https://cloudstudio.net/),使用腾讯云账号登录。 - 完成实名认证(如需长期使用…...

机器学习之心的创作纪念日
机缘 今天,是我成为创作者的第1460天。 在这段时间里,获得了很大的成长。 虽然日常忙碌但还在坚持创作、初心还在。 日常 创作已经成为我生活的一部分,尤其是在我的工作中,创作是不可或缺的,创作都是核心能力之一。…...

VeryReport和FastReport两款报表软件深度分析对比
在当今数据驱动的商业环境中,报表软件已经成为企业管理和数据分析的重要工具。无论是中小型企业还是大型企业,都需要依赖高效的报表工具来快速生成、分析和展示数据。市面上有许多报表工具,其中VeryReport和FastReport是两款备受关注的报表软…...

libtorch的c++,加载*.pth
一、转换模型为TorchScript 前提:python只保存了参数,没存结构 要在C中使用libtorch(PyTorch的C接口),读取和加载通过torch.save保存的模型( torch.save(pdn.state_dict()这种方式,只保存了…...

去除 RequestTemplate 对象中的指定请求头
目录 目标实现获取 RequestTemplate 对象去除请求头 目标 去除 RequestTemplate 对象中的指定请求头,如 Authorization 等。 实现 获取 RequestTemplate 对象 获取 RequestTemplate 对象的方式有很多种,如 通过 feign 虚拟客户端配置器: …...

b s架构 网络安全 网络安全架构分析
目录 文章目录 目录网络安全逻辑架构 微分段(Micro-segmentation)防火墙即服务(Firewall asa Service ,FWaaS)安全网络网关(Secure web gateway)净化域名系统(Sanitized Domain Na…...

【DeepSeek论文精读】2. DeepSeek LLM:以长期主义扩展开源语言模型
欢迎关注[【AIGC论文精读】](https://blog.csdn.net/youcans/category_12321605.html)原创作品 【DeepSeek论文精读】1. 从 DeepSeek LLM 到 DeepSeek R1 【DeepSeek论文精读】2. DeepSeek LLM:以长期主义扩展开源语言模型 【DeepSeek论文精读】3. DeepS…...

Spring Boot和SpringMVC的关系
Spring Boot和SpringMVC都是Spring框架的一部分,但它们的作用和使用方式有所不同。为了更好地理解它们的关系,我们可以从以下几个方面进行详细说明: 1. SpringBoot的作用 SpringBoot是一个开源框架,它的目的是简化Spring应用程序…...

java基础4(黑马)
一、方法 1.定义 方法:是一种语法结构,它可以把一段代码封装成一个功能,以便重复使用。 方法的完整格式: package cn.chang.define;public class MethodDemo1 {public static void main(String[] args) {// 目标:掌…...

nodejs - vue 视频切片上传,本地正常,线上环境导致磁盘爆满bug
nodejs 视频切片上传,本地正常,线上环境导致磁盘爆满bug 原因: 然后在每隔一分钟执行du -sh ls ,发现文件变得越来越大,即文件下的mp4文件越来越大 最后导致磁盘直接爆满 排查原因 1、尝试将m3u8文件夹下的所有视…...

注意力机制(Attention Mechanism)和Transformer模型的区别与联系
注意力机制(Attention Mechanism) 和 Transformer 模型 是深度学习领域中的两个重要概念,虽然它们紧密相关,但有着明显的区别。下面我们将从 定义、作用、结构 和 应用 等多个维度来分析这两者的区别与联系。 1. 定义 注意力机制(Attention Mechanism): 注意力机制是一…...

C++,设计模式,【单例模式】
文章目录 一、模式定义与核心价值二、模式结构解析三、关键实现技术演进1. 基础版(非线程安全)2. 线程安全版(双重检查锁)3. 现代C++实现(C++11起)四、实战案例:全局日志管理器五、模式优缺点深度分析✅ 核心优势⚠️ 潜在缺陷六、典型应用场景七、高级实现技巧1. 模板化…...

C++:类和对象初识
C:类和对象初识 前言类的引入与定义引入定义类的两种定义方法1. 声明和定义全部放在类体中2. 声明和定义分离式 类的成员变量命名规则 类的访问限定符及封装访问限定符封装 类的作用域与实例化类的作用域类实例化实例化方式: 类对象模型类对象的大小存储…...

官网下载Redis指南
1.访问官网 https://redis.io/downloads/#stack 2.点击redis图标 拉到下面点击download 在新页面拉到最下面,点击install from source 找到需要的大版本后,点击releases page 最后点击下载需要的版本号即可...

活动预告 |【Part1】 Azure 在线技术公开课:迁移和保护 Windows Server 和 SQL Server 工作负载
课程介绍 通过 Microsoft Learn 免费参加 Microsoft Azure 在线技术公开课,掌握创造新机遇所需的技能,加快对 Microsoft 云技术的了解。参加我们举办的“迁移和保护 Windows Server 和 SQL Server 工作负载”活动,了解 Azure 如何为将工作负…...

【Linux系统编程】五、进程创建 -- fork()
文章目录 前言Ⅰ. 重温fork函数一、fork()的概念二、如何理解fork()有两个返回值 Ⅱ.fork的常规用法Ⅲ. fork调用失败的原因Ⅳ. 写时拷贝为什么存在写时拷贝❓❓❓ 前言 现阶段我们知道进程创建有如下两种方式,其实包括在以后的学习中这两种方式也是最常见的&#…...

深入解析 STM32 GPIO:结构、配置与应用实践
理解 GPIO 的工作原理和配置方法是掌握 STM32 开发的基础,后续的外设(如定时器、ADC、通信接口)都依赖于 GPIO 的正确配置。 目录 一、GPIO 的基本概念 二、GPIO 的主要功能 三、GPIO 的内部结构 四、GPIO 的工作模式 1. 输入模式 2. 输出模式 3. 复用功能模式 4. 模…...

深入探究 C++17 std::is_invocable
文章目录 一、引言二、std::is_invocable 概述代码示例输出结果 三、std::is_invocable 的工作原理简化实现示例 四、std::is_invocable 的相关变体1. std::is_invocable_r2. std::is_nothrow_invocable 和 std::is_nothrow_invocable_r 五、使用场景1. 模板元编程2. 泛型算法 …...

Vmware网络模式
一、Vmware虚拟网络 Vmware共支持创建20个虚拟网络,相当于现实生活的交换机,名称vmnet0-vmnet19 没创建一个虚拟网络。对应在物理机会自动生成相应的虚拟网卡 该虚拟网卡用于和对应的虚拟网络中的虚拟机通信 二、虚拟网络的工作模式 1、nat模式 …...

神经辐射场(NeRF):从2D图像到3D场景的革命性重建
神经辐射场(NeRF):从2D图像到3D场景的革命性重建 引言 在计算机视觉和图形学领域,如何从有限的2D图像中高效且准确地重建真实的3D场景,一直是一个重要的研究方向。传统的3D重建方法,如多视角几何、点云重建…...

深入解析AI技术原理
序言 在当今数字化时代,人工智能(AI)已经成为科技领域最炙手可热的话题之一。从智能家居到自动驾驶汽车,从医疗诊断到金融风险预测,AI的应用无处不在。然而,对于许多人来说,AI背后的技术原理仍然充满了神秘色彩。本文将深入探讨AI的核心技术原理,从基础理论到前…...