【硬核】开源的高性能轻量级ORM框架

news2024/12/27 11:41:23

简介

easy-orm是一款简洁、轻量高效的数据库对象关系映射框架,它的代码编写规范基于SQL语义,学习成本低,可以快速掌握。

下图是与业界mybatis-plus框架相比。

功能mybatis-pluseasy-orm
单表CRUD
多表CRUD×
子查询x
多数据源×
预编译

easy-orm不需要做任何前置工作,不依赖于任何jar包,开箱即用,以下给出easy-orm的基本使用方式。

注册数据源

用户可以任意选择接入的连接池,以HikariCP为例,用户可以在任意地方获取到数据源。

    HikariConfig config = new HikariConfig();
    config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    config.setUsername("root");
    config.setPassword("xxxxxx");
    // easy-orm支持注册多数据源,此处注册了名为mysql的数据源,并且设置为默认数据源
    SqlConnectFactory.register("mysql", new HikariDataSource(config), true);

1. 查询

在实体类上添加@Table注解指定表名与数据库表相关联。

查询出所有姓张的学生,并且是18到30岁以内

List<StudentModel> studentModels = SqlExecutor.builder().selectChain()
        //.select() 等于 select *
        .select(StudentModel::getId, StudentModel::getName, StudentModel::getAge)
        .from(StudentModel.class)
        .where(SubUtil.like(StudentModel::getName, "张%").and().between(StudentModel::getAge, 18, 30))
        .list(StudentModel.class);

System.out.println(studentModels);

// 控制台输出
22:18:05.754 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - ==> execute sql: SELECT studentModel.id,studentModel.name,studentModel.age FROM student studentModel WHERE studentModel.name LIKE (?) AND studentModel.age BETWEEN ? AND ?
22:18:05.754 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - ==> param1=%, param2=18, param3=30
22:18:07.336 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - <==  total:2
[StudentModel{id='6', name='张三', age='26'}, StudentModel{id='7', name='张玉立', age='19'}]

2.更新

更新张三的年龄为18

boolean result = SqlExecutor.builder().updateChain()
                .update(StudentModel.class)
                .set(SubUtil.set(StudentModel::getAge, 18))
                .where(SubUtil.eq(StudentModel::getName, "张三"))
                .exec();

System.out.println("更新结果:" + result);

// 控制台输出
22:26:43.453 [Test worker] DEBUG com.coderevolt.sql.core.dml.DMLSqlGenerator - ==> execute sql: UPDATE student studentModel SET studentModel.age = ? WHERE studentModel.name = (?)
22:26:43.454 [Test worker] DEBUG com.coderevolt.sql.core.dml.DMLSqlGenerator - ==> param1=18, param2=张三
更新结果:true

3.删除

删除所有年纪小于10岁的学生

 boolean result = SqlExecutor.builder().deleteChain()
                .deleteFrom(StudentModel.class)
                .where(SubUtil.lt(StudentModel::getAge, 10))
                .exec();

System.out.println("执行结果: " + result);

// 控制台输出
22:30:42.835 [Test worker] DEBUG com.coderevolt.sql.core.dml.DMLSqlGenerator - ==> execute sql: DELETE FROM student studentModel WHERE studentModel.age < (?)
22:30:42.836 [Test worker] DEBUG com.coderevolt.sql.core.dml.DMLSqlGenerator - ==> param1=10
执行结果: true

4.新增

新增一条学生数据


boolean result = SqlExecutor.builder().insertChain()
//                .insertInto(StudentModel.class) 等于 insert into student
        .insertInto(StudentModel.class, StudentModel::getName, StudentModel::getAge)
        .values(new StudentModel("老王", 20))
        .exec();

        System.out.println("执行结果: " + result);

22:43:15.585 [Test worker] DEBUG com.coderevolt.sql.core.dml.DMLSqlGenerator - ==> execute sql: INSERT INTO student(name,age) VALUES (?,?)
22:43:15.586 [Test worker] DEBUG com.coderevolt.sql.core.dml.DMLSqlGenerator - ==> param1=老王, param2=20
执行结果: true

5. 多表查询

查询学生参与的课程

List<Map<String, Object>> listMap = SqlExecutor.builder().selectChain()
        .select(StudentModel::getName, StudentModel::getAge)
        .select(SubjectModel::getName, "subjectName")
        .from(StudentModel.class)
        .innerJoin(StudentSubjectRelation.class, SubUtil.eq(StudentModel::getId, StudentSubjectRelation::getStudentId))
        .innerJoin(SubjectModel.class, SubUtil.eq(StudentSubjectRelation::getSubjectId, SubjectModel::getId))
        .listMap();

System.out.println(listMap);

// 控制台输出
22:52:14.212 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - ==> execute sql: SELECT studentModel.name,studentModel.age,subjectModel.name AS subjectName FROM student studentModel INNER JOIN student_subject_relation studentSubjectRelation ON studentModel.id = studentSubjectRelation.student_id INNER JOIN subject subjectModel ON studentSubjectRelation.subject_id = subjectModel.id
22:52:14.231 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - <==  total:3
[{name=张三, age=18, subjectName=语文}, {name=张三, age=18, subjectName=数学}, {name=张玉立, age=19, subjectName=数学}]

6.子查询

查询参与课程的学生

SelectSqlGenerator sqlGenerator = SqlExecutor.builder(SqlOption.builder().build()).selectChain()
                .select(StudentModel::getName)
                .from(StudentModel.class)
                .where(SubUtil.in(StudentModel::getId, ctx -> {
                    return SubUtil.subSelect()
                            .select(StudentSubjectRelation::getStudentId)
                            .from(StudentSubjectRelation.class)
                            .innerJoin(SubjectModel.class, SubUtil.eq(StudentSubjectRelation::getSubjectId, SubjectModel::getId));
                }));
System.out.println(sqlGenerator.listMap());

// 控制台输出
22:59:06.024 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - ==> execute sql: SELECT studentModel.name FROM student studentModel WHERE studentModel.id IN (SELECT studentSubjectRelation.student_id FROM student_subject_relation studentSubjectRelation INNER JOIN subject subjectModel ON studentSubjectRelation.subject_id = subjectModel.id)
22:59:06.042 [Test worker] DEBUG com.coderevolt.sql.core.dql.DQLSqlGenerator - <==  total:2
[{name=张三}, {name=张玉立}]

其他

easy-orm同样支持批量新增和批量更新,其中批量更新可以通过@Column注解指定ID属性和更新策略,例如StudentModel对象

@Table("student")
public class StudentModel {

    /**
     * @see com.coderevolt.sql.core.dml.UpdateSqlGenerator#updateById
     */
    @Column(type = Column.ColumnType.ID)
    private Long id;

    /**
     * @Column注解缺省默认行为:Column.DmlStrategy.IGNORE_NULL
     */
    private String name;

    @Column(dmlStrategy = Column.DmlStrategy.IGNORE_NULL)
    private Integer age;

    /**
     * Column.DmlStrategy.IGNORE_NULL 忽略null值,当avatar为null时忽略更新数据库,默认行为
     */
    @Column(dmlStrategy = Column.DmlStrategy.IGNORE_NULL)
    private String hobby;

    /**
     * Column.DmlStrategy.SET_NULL 不忽略null值,当avatar为null时更新数据库
     */
    @Column(dmlStrategy = Column.DmlStrategy.SET_NULL)
    private String avatar;
}

项目中封装了SubUtil工具类,提供了sql便捷操作方法,用户完全可以再进行扩展。AtomicUtil类提供了事务执行的方法。

项目的整体设计架构很简洁清晰,每个sql操作都是通过SqlExecutor类创建对应的sql执行链路,在builder方法中可以设置SqlOption 类来配置本次执行,或者使用默认的配置。在这个链路中会创建一个上下文容器SqlChainContext类存放所有的信息。
子查询同样可以看作是没有执行动作(例如exec()、listMap())的执行链,执行链的上下文信息会在嵌套子查询之间传递。
在这里插入图片描述

每一个子操作都被抽象成AbstractSub类的子类,并实现apply抽象方法。
子操作可以分为三大类:compare(where、havaing、on)、order(order by)、set(update set)
在这里插入图片描述

其中apply抽象方法会接收到上层执行链的上下文信息,并返回子操作的sql语句,以SubOrder为例。

@Override
public String apply(SqlChainContext ctx) {
    this.sqlBuf.append(SFuncUtil.getColumn(column));
    if (sqlSort != null) {
        this.sqlBuf.append(" ").append(sqlSort.name());
    }
    return toSql();
}

jmeter性能测试参考
在这里插入图片描述

最后

在开发完这个orm后我在想,能不能无感知的join和嵌套不同的数据源,屏蔽数据源的差异,就像是操作单数据源那样简单。

github地址: https://github.com/songbiaoself/easy-orm

gitee地址: https://gitee.com/song_biao/easy-orm

联系方式: 646997146@qq.com

公众号: codeRevolt

在这里插入图片描述

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

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

相关文章

一文带你深度了解FreeRTOS信号量——二值信号量

本篇文章深度讲述FreeRTOS信号量——二值信号量的知识&#xff0c;希望我的分享对你有所帮助&#xff01; 关于FreeRTOS信号量的相关介入&#xff0c;大家可以参考一下这篇文章&#xff1a; 一文带你初探FreeRTOS信号量_freertos 二进制信号量-CSDN博客 目录 一、二值信号量简…

25届最近5年自动化考研院校分析

哈尔滨工程大学 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、初试大纲复试大纲 七、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指定教材 1、考试科目介绍 2、指定…

顺序结构就是“千里走单骑”

顺序结构&#xff0c;就是把工作分成若干个步骤&#xff0c;然后让计算机按步骤依次执行。 对于代码而言&#xff0c;顺序结构就是从上到下依次执行每一条语句。 #include<stdio.h>int main(){//The steps of putting an elephant into the fridge.printf("First,…

【Python知识宝库】掌握列表与元组,轻松处理数据集合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在Python编程中&#xff0c;列表&#xff08;List&#xff09;和元组&#xff08;Tuple&#xff09;是两种非常基础且强大…

Unity实战案例 2D小游戏HappyGlass(游戏管理类脚本)

本案例素材和教程都来自Siki学院&#xff0c;十分感谢教程中的老师 本文仅作学习笔记分享交流&#xff0c;不作任何商业用途 基础效果 游戏管理脚本 using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using Uni…

FineBI修改地图配置

前言 在使用FineBI绘制地图时&#xff0c;有时候我们可能发现FineBI中的默认地图模型不是最新的&#xff0c;导致某些地区的区域地图与现实不一致&#xff0c;比如说FineBI的默认地图中深圳地图没有大鹏新区&#xff0c;并且将现在大鹏新区的地方标记为了龙华区&#xff0c;为…

Leetcode19删除链表的倒数第K个节点(java实现)

今天分享的题目如下&#xff1a; 说一下我们的解题思路&#xff1a;我们要想删除第k个节点&#xff0c;那么指针必须落在k-1节点上&#xff0c;比如我们想要操作题目中的节点4&#xff0c;那么指针必须落在节点3&#xff0c;然后让节点3.next 3.next.next即可。 所以明白了这个…

【精选】计算机毕业设计之:基于springboot汽车租赁系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

推荐3款免费的数据恢复软件,从此再也不怕数据丢失

Handy Recovery Handy Recovery是一款功能强大且易于使用的数据恢复软件&#xff0c;能够帮助用户恢复因误删、病毒攻击、系统崩溃等原因丢失的数据。该软件支持多种文件系统&#xff0c;包括FAT12/16/32、NTFS、NTFS5以及HFS等。它不仅可以从硬盘、闪存驱动器、U盘等设备中恢复…

Linux学习(13)计算机网络基础概论

本节学习内容 1.网络的基本概念&#xff08;网络、互联网、IP地址、MAC地址、常用网络协议&#xff09; 2.网络分层模型&#xff08;OS的7层模型与tcp/ip协议族体系4层结构、数据链路层、网络层、传输层、应用层&#xff09; 3.网络应用程序通信流程 一、网络的基本概念 1…

python可视化-直方图

1、加载数据 import pandas as pd from sklearn.datasets import load_iris import warnings# 禁用所有警告信息 warnings.filterwarnings(ignore)# 加载数据 iris load_iris() iris iris.keys() df pd.DataFrame(iris.data, columnsiris.feature_names) df[target] iris.t…

联华证券_股票特大单买入意味什么,主力入市

“股票特大单买入”通常意味着有大量资金集中在某一时刻涌入该股票&#xff0c;这往往被视为主力资金入市的迹象。以下是这一现象的详细解读&#xff1a; 1. 主力资金入市 特大单买入: 指的是单笔大额资金买入某只股票&#xff0c;通常是由机构投资者或其他大资金操盘者进行的…

动手学深度学习(pytorch)学习记录19-参数管理[学习记录]

文章目录 参数访问目标参数一次性访问所有参数从嵌套块收集参数 参数初始化内置初始化自定义初始化 参数绑定延后初始化 本节内容&#xff1a; 访问参数&#xff0c;用于调试、诊断和可视化&#xff1b; 参数初始化&#xff1b; 在不同模型组件间共享参数&#xff1b; 延后初始…

C++必修:unordered_set与unordered_map的实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. unordered_set与unordered_map的结构 我们知道STL中的unordered_set与unorder…

PowerDesigner生成数据库表结构

PowerDesigner生成数据库表结构 目录 1. 安装32位JDK 2. 更改当前DBMS 3. 下载MySQL驱动 4. 生成数据库表结构 安装32位JDK PowerDesigner只支持32位JDK 更改当前DBMS 下载MySQL驱动 下载地址&#xff1a; MySQL :: Begin Your Download 生成数据库表结构 选择Dire…

同城外卖系统开发方案解析

外卖系统开发是一个复杂而细致的过程&#xff0c;涉及多个方面的考虑和技术实现。以下是对外卖系统开发的详细解析&#xff1a; 一、需求分析 在开发外卖系统之前&#xff0c;首先需要进行详尽的需求分析。这包括用户需求、商家需求和后台管理需求三个方面&#xff1a; 用户需…

怎样把两个pdf合并成一个pdf?教你7种方法轻松完成合并!

新手小白如何将pdf合并成一个文件&#xff1f;pdf是目前较为主流的一种传输格式&#xff0c;内容包含了丰富的多媒体数据&#xff0c;包括文本、图像、表格等多种元素&#xff0c;很多企业和教育工作者都喜欢使用pdf格式。 pdf文件体积较小&#xff0c;兼容性高&#xff0c;平…

微深节能 卸料小车远程智能控制系统 格雷母线定位系统

微深节能的卸料小车远程智能控制系统与格雷母线定位系统的结合&#xff0c;为物料管理提供了智能化、精准化、高效化的解决方案。 一、系统概述 卸料小车远程智能控制系统&#xff1a;该系统利用现代科技手段&#xff0c;实现对卸料小车的远程监控与智能控制&#xff0c;旨在提…

使用vueuse在组件内复用模板

1. 安装vueusae pnpm i vueuse/core2. 组件内复用模板 createReusableTemplate 是vueuse中的一个实用工具&#xff0c;用于在 Vue 3 中创建可重复使用的模板片段&#xff0c;同时保持状态的独立性。这对于需要在多个组件中重复使用相同的结构和逻辑时非常有用。 因为这些可复…

基于ROM的VGA显示

前言 在早期计算机和嵌入式系统中&#xff0c;图形显示和用户界面的实现主要依赖于硬件技术。VGA&#xff08;视频图形阵列&#xff09;标准在1980年代中期成为主流图形显示技术&#xff0c;其高分辨率和良好的兼容性使其在计算机显示领域中占据了重要地位。VGA标准支持640x480…