Java/Kotlin双语革命性ORM框架Jimmer(一)——介绍与简单使用

news2025/2/11 9:33:07

概览

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();

    @Nullable
    Integer 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)
    @Nullable
    User user();

    @IdView("user")
    Integer userId();

}

配置数据库链接

applicantion.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://myhost:3306/my_jimmer
    username: root
    password: root

jimmer:
  dialect: org.babyfish.jimmer.sql.dialect.MySqlDialect
  show-sql: on
  pretty-sql: true
  database-validation:
    schema: my_jimmer

构建

Maven build

查询

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private 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 name

    like(name) as likename
}

构建

Maven build

使用specification查询

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private 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.coloradmin.cn/o/2295499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剪辑学习整理

文章目录 1. 剪辑介绍 1. 剪辑介绍 剪辑可以干什么&#xff1f;剪辑分为哪些种类&#xff1f; https://www.bilibili.com/video/BV15r421p7aF/?spm_id_from333.337.search-card.all.click&vd_source5534adbd427e3b01c725714cd93961af 学完剪辑之后如何找工作or兼职&#…

IDEA查看项目依赖包及其版本

一.IDEA将现有项目转换为Maven项目 在IntelliJ IDEA中,将现有项目转换为Maven项目是一个常见的需求,可以通过几种不同的方法来实现。Maven是一个强大的构建工具,它可以帮助自动化项目的构建过程,管理依赖关系,以及其他许多方面。 添加Maven支持 如果你的项目还没有pom.xm…

centos虚拟机迁移没有ip的问题

故事背景&#xff0c;我们的centos虚拟机本来是好好的&#xff0c;但是拷贝到其他电脑上就不能分配ip&#xff0c;我个人觉得这个vmware他们软件应该搞定这个啊&#xff0c;因为这个问题是每次都会出现的。 网络选桥接 网络启动失败 service network restart Restarting netw…

Java 大视界 -- Java 大数据在智能供应链中的应用与优化(76)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

赛博算命之 ”梅花易数“ 的 “JAVA“ 实现 ——从玄学到科学的探索

hello~朋友们&#xff01;好久不见&#xff01; 今天给大家带来赛博算命第三期——梅花易数的java实现 赛博算命系列文章&#xff1a; 周易六十四卦 掐指一算——小六壬 更多优质文章&#xff1a;个人主页 JAVA系列&#xff1a;JAVA 大佬们互三哦~互三必回&#xff01;&#xf…

即梦(Dreamina)技术浅析(六):多模态生成模型

多模态生成模型是即梦(Dreamina)的核心技术之一,旨在结合文本和图像信息,生成更符合用户需求的视觉内容。多模态生成模型通过整合不同类型的数据(如文本和图像),能够实现更丰富、更精准的生成效果。 1. 基本原理 1.1 多模态生成模型概述 多模态生成模型的目标是结合不…

递增三元组(蓝桥杯18F)

暴力求解&#xff1a; #include<iostream> using namespace std; int main() {int N;cin >> N;int* A new int[N];int* B new int[N];int* C new int[N];for (int i 0; i < N;i) {cin >> A[i];}for (int i 0; i < N; i) {cin >> B[i];}for…

计算机毕业设计SparkStreaming+Kafka广告推荐系统 广告预测 广告数据分析可视化 广告爬虫 大数据毕业设计 深度学习 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

FreeCAD创建零件(系列1)

1、新建草图绘制1个矩形 2、画1个半圆弧 3、增加一个约束点 4、标注距离 5、将线段转为辅助线 将图中的线段切换为辅助线,线条颜色之后转为蓝色线。 6、离开草图

韶音科技:消费电子行业售后服务实现数字化转型,重塑客户服务体系

韶音科技&#xff1a;消费电子行业售后服务实现数字化转型&#xff0c;重塑客户服务体系 在当今这个科技日新月异的时代&#xff0c;企业之间的竞争早已超越了单纯的产品质量比拼&#xff0c;**售后服务成为了衡量消费电子行业各品牌实力与客户满意度的关键一环。**深圳市韶音…

mes系统对工业数字化转型起到重要作用,它的实际应用有哪些

一、生产计划与调度 在工业数字化转型中&#xff0c;MES 系统能够对生产计划进行高效的管理和调度。通过与企业资源计划&#xff08;ERP&#xff09;系统的集成&#xff0c;MES 可以获取生产订单信息&#xff0c;并根据生产设备的状态、人员安排以及物料供应情况等因素&#x…

网络安全:挑战、技术与未来发展

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 在数字化时代&#xff0c;网络安全已成为全球关注的焦点。随着互联网的普及和信息技术的高速发展&#xff0c;网络攻击的…

从零开始玩转Docker:轻松开启容器化之旅

一、什么是 Docker Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。简单来说&#xff0c;Docker 就像是一个超级 “快递箱”&#xff0c…

Python Pandas(5):Pandas Excel 文件操作

Pandas 提供了丰富的 Excel 文件操作功能&#xff0c;帮助我们方便地读取和写入 .xls 和 .xlsx 文件&#xff0c;支持多表单、索引、列选择等复杂操作&#xff0c;是数据分析中必备的工具。 操作方法说明读取 Excel 文件pd.read_excel()读取 Excel 文件&#xff0c;返回 DataF…

【计组】实验五 J型指令设计实验

目录 一、实验目的 二、实验环境 三、实验原理 四、实验任务 代码 一、实验目的 1. 理解MIPS处理器指令格式及功能。 2. 掌握lw, sw, beq, bne, lui, j, jal指令格式与功能。 3. 掌握ModelSim和ISE\Vivado工具软件。 4. 掌握基本的测试代码编写和FPGA开发板使用方法。 …

Redis03 - 高可用

Redis高可用 文章目录 Redis高可用一&#xff1a;主从复制 & 读写分离1&#xff1a;主从复制的作用2&#xff1a;主从复制原理2.1&#xff1a;全量复制2.2&#xff1a;增量复制&#xff08;环形缓冲区&#xff09; 3&#xff1a;主从复制实际演示3.1&#xff1a;基本流程准…

SAP HCM自定义开发程序调用odata api 如何ping外网

网络&#xff1a;我们知道SAP系统一般是部署在内网&#xff0c;Successfactors是云系统&#xff0c;部署在公有云上面&#xff0c;那肯定是公网&#xff0c;那内网和外网数据传递就需要网络做相关的设置&#xff0c;今天遇到的问题是网络说已经把SAP系统映射到公网&#xff0c;…

SAP HCM PFCG读取结构化权限参数

权限&#xff1a;HCM的权限分两套&#xff0c;一套是PFCG的普通权限&#xff0c;一套是结构化权限是根据组织ID限制访问权限的&#xff0c;今天我们讨论的话题如何把这两类的权限组合起来 场景&#xff1a;例如下载有个薪酬管理人员&#xff0c;他复制A和B部门&#xff0c;但是…

Ubuntu 20.04配置网络

1&#xff0c;检查自己网络是否配通。 网络配置成功显示的网络图标 不成功的网络图标 如果看不见网络图标&#xff0c;可以使用ping命令。连接一下百度网。 ping www.baidu.com ping失败的样子 ping成功的样子 2&#xff0c;接下来进入正题&#xff0c;我们开始配置网络。 这…

【hive】记一次hiveserver内存溢出排查,线程池未正确关闭导致

一、使用 MemoryAnalyzer软件打开hprof文件 很大有30G&#xff0c;win内存24GB&#xff0c;不用担心可以打开&#xff0c;ma软件能够生成索引文件&#xff0c;逐块分析内存&#xff0c;如下图。 大约需要4小时。 overview中开不到具体信息。 二、使用Leak Suspects功能继续…