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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966333.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

deepseek+kimi自动生成ppt

打开deepseek官网&#xff0c;输入详细的需求&#xff0c;让他生成个ppt 接着deepseek开始思考生成了 接着复制生成了的内容 打开kimi粘贴刚才deepseek生成的内容 可以一键生成啦&#xff0c;下载编辑使用吧

C#中深度解析BinaryFormatter序列化生成的二进制文件

C#中深度解析BinaryFormatter序列化生成的二进制文件 BinaryFormatter序列化时,对象必须有 可序列化特性[Serializable] 一.新建窗体测试程序BinaryDeepAnalysisDemo,将默认的Form1重命名为FormBinaryDeepAnalysis 二.新建测试类Test Test.cs源程序如下: using System; us…

探索从传统检索增强生成(RAG)到缓存增强生成(CAG)的转变

在人工智能快速发展的当下&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已成为众多应用的核心技术。检索增强生成&#xff08;RAG&#xff09;&#xff08;RAG 系统从 POC 到生产应用&#xff1a;全面解析与实践指南&#xff09;和缓存增强生成&#xff08;CAG&#x…

采用idea中的HTTP Client插件测试

1.安装插件 采用idea中的HTTP Client插件进行接口测试,好处是不用打开post/swagger等多个软件,并且可以保存测试时的参数,方便后续继续使用. 高版本(2020版本以上)的idea一般都自带这个插件,如果没有也可以单独安装. 2.使用 插件安装完成(或者如果idea自带插件),会在每个Con…

WebStorm设置Vue Component模板

下载vue.js插件 下面有模板样例 Composition API&#xff1a;这是 Vue 3 的一项新特性&#xff0c;允许通过 setup 函数来组织组件逻辑。Options API&#xff1a;这是 Vue 2 和 Vue 3 都支持的传统方式&#xff0c;通过定义组件的 data、methods、computed 等来组织逻辑。 Comp…

程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<7>

大家好啊&#xff0c;我是小象٩(๑ω๑)۶ 我的博客&#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家&#xff0c;希望能够和大家一起交流学习&#xff0c;共同进步。 今天我们一起来学习转移表&#xff0c;回调函数&#xff0c;qsort… 目录 一、转移表1.1 定义与原理1.3…

DeepSeek-R1:通过纯强化学习提升大模型推理能力,对于真正的强 AI (AGI/ASI),要放弃人类评审,让TA学会自我评估与博弈

DeepSeek-R1&#xff1a;通过纯强化学习提升大模型推理能力&#xff0c;对于真正的超级人工智能&#xff0c;要放弃人类评审&#xff0c;让TA学会自我评估与博弈 论文大纲理解Why - 这个研究要解决什么现实问题What - 核心发现或论点是什么HowHow good - 研究的理论贡献和实践意…

LabVIEW2025中文版软件安装包、工具包、安装教程下载

下载链接&#xff1a;LabVIEW及工具包大全-三易电子工作室http://blog.eeecontrol.com/labview6666 《LabVIEW2025安装图文教程》 1、解压后&#xff0c;双击install.exe安装 2、选中“我接受上述2条许可协议”&#xff0c;点击下一步 3、点击下一步&#xff0c;安装NI Packa…

使用 Ollama 在 Windows 环境部署 DeepSeek 大模型实战指南

文章目录 前言Ollama核心特性 实战步骤安装 Ollama验证安装结果部署 DeepSeek 模型拉取模型启动模型 交互体验命令行对话调用 REST API 总结个人简介 前言 近年来&#xff0c;大语言模型&#xff08;LLM&#xff09;的应用逐渐成为技术热点&#xff0c;而 DeepSeek 作为国产开…

快速在wsl上部署学习使用c++轻量化服务器-学习笔记

知乎上推荐的Tinywebserver这个服务器&#xff0c;快速部署搭建&#xff0c;学习c服务器开发 仓库地址 githubhttps://link.zhihu.com/?targethttps%3A//github.com/qinguoyi/TinyWebServerhttps://link.zhihu.com/?targethttps%3A//github.com/qinguoyi/TinyWebServer 在…

【R语言】apply函数族

在R语言中使用循环操作时是使用自身来实现的&#xff0c;效率较低。所以R语言有一个符合其统计语言出身的特点&#xff1a;向量化。R语言中的向量化运用了底层的C语言&#xff0c;而C语言的效率比高层的R语言的效率高。 apply函数族主要是为了解决数据向量化运算的问题&#x…

spring 学习(工厂方式 实例化对象(静态工厂,实例化工厂,实现factorybean 规范))

目录 前言 第一种&#xff1a;静态工厂方式实例化对象 静态工厂的特点 demo(案例&#xff09; 第二种&#xff1a;实例工厂的方式 实例工厂和静态工厂的区别 demo(案例&#xff09; 第三种&#xff1a;实现FactoryBean规范的方式 demo(案例&#xff09; 前言 spring 实…

4.python+flask+SQLAlchemy+达梦数据库

前提 1.liunx Centos7上通过docker部署了达梦数据库。从达梦官网下载的docker镜像。(可以参考前面的博文) 2.windows上通过下载x86,win64位的达梦数据库,只安装客户端,不安装服务端。从达梦官网下载达梦数据库windows版。(可以参考前面的博文) 这样就可以用windows的达…

2024最新版Java面试题及答案,【来自于各大厂】

发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全~ 篇幅限制就只能给大家展示小册部分内容了&#xff0c;需要完整版的及Java面试宝典小伙伴点赞转发&#xff0c;关注我后在【翻到最下方&#xff0c;文尾点击名片】即可免费获取…

接入 deepseek 实现AI智能问诊

1. 准备工作 注册 DeepSeek 账号 前往 DeepSeek 官网 注册账号并获取 API Key。 创建 UniApp 项目 使用 HBuilderX 创建一个新的 UniApp 项目&#xff08;选择 Vue3 或 Vue2 模板&#xff09;。 安装依赖 如果需要在 UniApp 中使用 HTTP 请求&#xff0c;推荐使用 uni.requ…

TypeScript 中的对象类型:深入理解接口和类型别名

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Vinorine合成酶的晶体结构-文献精读110

Crystal structure of vinorine synthase, the first representative of the BAHD superfamily Vinorine合成酶的晶体结构&#xff1a;BAHD超级家族的首个代表 摘要 Vinorine合成酶是一种酰基转移酶&#xff0c;在植物Rauvolfia中抗心律失常单萜吲哚生物碱ajmaline的生物合成…

Kokoro 开源文本转语音引擎上线!多语言支持,无需联网,浏览器内极速运行

Kokoro 是一款轻量级的开源文本转语音(TTS)引擎,凭借其高效能和轻量化设计,迅速在技术社区中引起关注。本文将详细介绍 Kokoro 的主要特点,并提供在浏览器和 Python 环境中的代码示例,帮助您快速上手。 1. Kokoro:可在浏览器中运行的 TTS 引擎 1.1 简介 Kokoro 是一个…

Qt+海康虚拟相机的调试

做机器视觉项目的时候&#xff0c;在没有相机或需要把现场采集的图片在本地跑一下做测试时&#xff0c;可以使用海康的虚拟相机调试。以下是设置步骤&#xff1a; 1.安装好海康MVS软件&#xff0c;在菜单栏->工具选择虚拟相机工具&#xff0c;如下图&#xff1a; 2.打开虚拟…

38、【OS】【Nuttx】OSTest分析(3):参数传递

背景 接之前 blog 36、【OS】【Nuttx】OSTest分析&#xff08;2&#xff09;&#xff1a;环境变量测试 37、【OS】【Nuttx】OSTest分析&#xff08;2&#xff09;&#xff1a;任务创建 分析完环境变量测试&#xff0c;和任务创建的一些关键要素&#xff0c;OSTest 进入下一阶段…