ORM 技术的终结者

简介: ORM技术如Hibernate、Mybatis和JOOQ简化了Java开发中的数据库操作,但它们在处理复杂计算时表现不佳。esProc SPL是一种基于Java的开源工具,通过提供一种新的脚本语言SPL,弥补了Java在处理复杂数据计算上的不足。SPL不仅支持丰富的数据计算函数,还能无缝集成到Java应用中,实现更简洁、高效的数据库操作和业务逻辑处理。此外,SPL支持多种数据源,提供强大的调试工具,适合频繁变化的业务需求。

Hibernate,Mybatis 以及新兴的 JOOQ 等 ORM 技术能够方便地将数据库表映射成 Java 对象,并提供自动读写能力。ORM 技术使得用 Java 开发数据库应用变得更为高效。
不过,映射数据表仅仅是最基础的一环,业务逻辑的开发还会涉及很多流程控制和数据计算的工作。流程控制是 Java 的强项,没什么压力;但批量结构化数据计算却一直是 Java 的弱项,直接用 Java 编程会非常繁琐。
遗憾的是,这些 ORM 技术提供的计算能力也不如人意。Hibernate 几乎完全依赖于从 HQL 转换出 SQL,而 HQL 只能对应 SQL 的一个很小子集,计算能力严重不如;JOOQ 要强很多,以 Java 风格提供了不少基础运算,比如过滤、分组等,这也是近年来它能超越 Hibernate 的原因之一,但代码的简洁程度仍然比不上 SQL。

在 Java 下开发数据库应用,esProc SPL 是个更好的选择。
esProc SPL 是个 Java 编写的开源软件,因为是纯 Java 软件,esProc 可以和 ORM 一样被完全无缝地集成进 Java 应用中,一起享受成熟 Java 框架的优势。

与 ORM 技术不同,esProc 基于 JVM 提供了一种新的程序语言 SPL 用于编程,而不是直接使用 Java。SPL 脚本通过 esProc 提供的 JDBC 接口被 Java 程序调用,就像调用数据库 SQL 或存储过程一样。

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = conn.createStatement();
ResultSet result = statement.executeQuery("=T(\"Orders.csv\").select(Amount>1000 && 
like(Client,\"*s*\")

为什么要设计一种新的程序语言而不直接封装成 Java API 呢?
Java 是编译型的静态语言,在这个基础上很难实现动态数据结构和便捷的 Lambda 语法,而这又是结构化数据运算中特别常见的,也是 SQL 的优势所在。
SQL 中任何一个 SELECT 语句都会产生一个新的数据结构,可以随意添加删除字段,而不必事先定义结构(类),这在结构化数据运算中家常便饭。但 Java 这类语言却不行,在代码编译阶段就要把用到的结构(类)都定义好,可以认为不能在执行过程中动态产生新的类(Java 理论上支持动态编译,但复杂度太大)。如果用一个专门的类来表示所有数据表,把字段名也作为类的数据成员,这又不能直接使用类的属性语法来引用字段,代码非常麻烦。
Lambda 语法是在 SQL 中大量使用,比如 WHERE 中的条件,本质上就是个 Lambda 表达式。Java 这种静态语言虽然现在也支持 Lambda 语法,但方便程度远远不如 SQL。每次书写时还是要有个函数头定义来告诉编译器现在要写 Lambda 函数了,代码看着很乱。在 Lambda 函数中也不能直接引用数据表的字段名,比如用单价和数量计算金额时,如果用于表示当前成员的参数名为 x,则需要写成 "x. 单价 x. 数量" 这种啰嗦的形式。而在 SQL 中可以更为直观地写成 "单价 数量"。
解释型的动态语言才能实现 SQL 的这些特征,可以随时生成新的数据结构,也可以根据宿主函数本身决定当前参数是不是 Lambda 函数,从而没必要写个定义头,更可以根据上下文正确引用未写表名的字段。
SQL 是解释型动态语言,SPL 也是。Java 不是,所以用 Java 很难写出简洁的代码,无论怎样提供 API 都不行。

在解释型动态语言基础上,SPL 提供了比 SQL 更完善的结构化数据对象(表、记录、游标)和更丰富的计算函数,包括 SQL 中有的过滤、分组、连接等基本运算,还有 SQL 中缺失的有序、集合等运算。所以,SPL 代码通常会比 SQL 更简洁易维护,比 ORM 基础上的 Java 代码就更强得多。下面是一些简单对比(这里只用计算能力最强的 JOOQ 举例):
过滤

SQL: select * from Orders where ((SellerID=2 and Amount<3000) or (SellerID=3 and Amount>=2000 and Amount<5000)) and year(OrderDate)>2010
SPL: Orders.select( ((SellerID==2 && Amount<3000) || (SellerID==3 && Amount>=2000 && Amount<5000)) && year(OrderDate)>2010)
JOOQ: context.select().from(ORDERS)
    .where(((ORDERS.SELLERID.equal(2).and(ORDERS.AMOUNT.lessThan(3000.0)))
    .or((ORDERS.SELLERID.equal(3).and(ORDERS.AMOUNT.greaterOrEqual(2000.0)
    .and(ORDERS.AMOUNT.lessThan(5000.0)))))).and(year(ORDERS.ORDERDATE).greaterThan(2012)))
    .fetch();

分组

SQL: select Client, extract(year from OrderDate) y,count(1) cnt from Orders group by Client, extract(year from OrderDate) having amt<20000
SPL: Orders.groups(Client,year(OrderDate):y;sum(Amount):amt,count(1):cnt).select(amt<20000)
JOOQ: context.select(ORDERS.CLIENT,year(ORDERS.ORDERDATE).as("y"),sum(ORDERS.AMOUNT).as("amt"),count(one()).as("cnt"))
    .from(ORDERS)
    .groupBy(ORDERS.CLIENT,year(ORDERS.ORDERDATE))
    .having(field("amt").lessThan(20000)).fetch();

更复杂一些的任务,比如这个任务,计算一支股票最长连续上涨的天数。这时候用 SQL 写就繁琐很多,而且很难难懂:

select max(ContinuousDays) from (
    select count(*) ContinuousDays from (
        select sum(UpDownTag) over (order by TradeDate) NoRisingDays from (
            select TradeDate,case when Price>lag(price) over ( order by TradeDate) then 0 else 1 end UpDownTag from Stock ))
    group by NoRisingDays )

JOOQ 也要运用窗口函数,写出来比 SQL 更复杂:

WindowDefinition woDay1 = name("woDay").as(orderBy(Stock.TradeDate));
Table<?>T0 = table(select(Stock.TradeDate.as("TradeDate"),when(Stock.Price.greaterThan(lag(Stock.Price).over(woDay1)),0).otherwise(1).as("risingflag")).from(Stock).window(woDay1)).as("T0");
WindowDefinition woDay2 = name("woDay1").as(orderBy(T0.field("TradeDate")));
Table<?>T1=table(select(sum(T0.field("UpDownTag").cast(java.math.BigDecimal.class)).over(woDay2).as("NoRisingdDys")).from(T0).window(woDay2)).as("T1");
Table<?>T2=table(select(count(one()).as("ContinuousDays")).from(T1).groupBy(T1.field("NoRisingDays"))).as("T2");
Result<?> result=context.select(max(T2.field("ContinuousDays"))).from(T2).fetch();

同样的计算逻辑,而用 SPL 就非常简单:

Stock.sort(TradeDate).group@i(Price<Price\[-1\]).max(~.len())

方便地读写数据库是 ORM 技术的基本功能,这方面 SPL 当然也没有问题:

Hibernate:
    String hql ="from OrdersEntity where sellerId=10";
    Query query = session.createQuery(hql);
    List<OrdersEntity> orders = query.list();

    Transaction tx = session.beginTransaction();
    for ( int i=0; i<orders.size(); i++ ) {
   
        session.save(orders.get(i));
    }
    tx.commit();

JOOQ:
    java.sql.Connection conn = DriverManager.getConnection(url, userName, password);
    DSLContext context = DSL.using(conn, SQLDialect.MYSQL);
    Result<OrdersRecord> R1=context.select().from(ORDERS).fetchInto(ORDERS);

    R1.forEach(r->{
   r.setValue(ORDERS.AMOUNT,r.getValue(ORDERS.AMOUNT).doubleValue()+100);}); 
    R1.forEach(r->{
   r.update();});

SPL:
    T=db.query("select * from test.Orders where sellerId=?",10)
    db.update(T,orders)
    db.commit()

这些功能区别不大,SPL 因为有前述的语言方面优势,仍然更简单一点。

SPL 本身有完善的流程控制语句,像 for 循环,if 分支都不在话下,还支持子程序调用。只用 SPL 就能实现非常复杂的业务逻辑,直接构成完整的业务单元,不需要上层 Java 代码来配合,主程序只要简单地调用 SPL 脚本就可以了。这相当于把存储过程从数据库中移到了 Java 中。

SPL 是纯 Java 程序,它可以被 Java 调用,也可以调用 Java。这样即便有个别用 SPL 不易实现而要使用 Java 实现的代码(比如某些对外的接口)或者已经有的现成 Java 代码,也都可以再集成进 SPL 中。SPL 脚本和主 Java 应用程序可以融为一体。

作为解释型语言,SPL 脚本可以存储成文件,置于主应用程序之外,代码修改可以独立进行且立即生效,不像基于 ORM 技术写的代码在修改后还要和主程序一起重新编译,整个应用都要停机重启。这样可以做到业务逻辑的热切换,特别适合支持变化频繁的业务。

2a89d8d5b6aa8936d6b3a62f5489f32a_3ed946ba9ad942fba3dc0fac88683c78_clipboard.png

SPL 支持的数据源也很丰富,无论关系数据库还是 NoSQL 或者 Kafak、Restful,无论是常规二维表还是多层次的 json,SPL 都可以计算直接读取后处理。而 ORM 技术一般只能针对关系数据库,无法直接支持其它数据源了。
a86a335245f63209dda3c999f00aecfb_3a7025c819254afeaec264d0793c926e_clipboard.png

非常特别地,SPL 代码写在格子里,这和通常写成文本的代码很不一样。独立的开发环境简洁易用,提供单步执行、设置断点、所见即所得的结果预览,调试开发也比 Java 更方便。

978d7db210c4b0ba65831a6c06b171f6_f45f4fa575d74c08bcc8702a3ce55951_clipboard.png

这里 写在格子里的程序语言 有对 SPL 有更详细的介绍。

SPL以开源免费,欢迎前往乾学院了解更多!

相关文章
|
11月前
|
人工智能 算法 测试技术
Insight-V:腾讯联合南洋理工、清华大学推出提升长链视觉推理能力的多模态模型
Insight-V是由南洋理工大学、腾讯公司和清华大学联合推出的多模态模型,旨在提升长链视觉推理能力。通过渐进式数据生成、多智能体系统和两阶段训练流程,Insight-V在多个视觉推理基准测试中表现出色,展现出强大的视觉推理能力。
255 42
Insight-V:腾讯联合南洋理工、清华大学推出提升长链视觉推理能力的多模态模型
|
11月前
|
安全 Anolis
龙蜥社区落地开源生态发展合作倡议,构建开放兼容的操作系统生态
通过共同努力,三个社区基于服务器操作系统场景,在操作系统内核等关键共性技术链统一方面达成了一致。
|
11月前
|
机器学习/深度学习 人工智能 自然语言处理
DiffSensei:AI 漫画生成框架,能生成内容可控的黑白漫画面板,支持多角色和布局控制
DiffSensei 是一个由北京大学、上海AI实验室及南洋理工大学共同推出的AI漫画生成框架,能够生成可控的黑白漫画面板。该框架整合了基于扩散的图像生成器和多模态大型语言模型(MLLM),支持多角色控制和精确布局控制,适用于漫画创作、个性化内容生成等多个领域。
816 19
DiffSensei:AI 漫画生成框架,能生成内容可控的黑白漫画面板,支持多角色和布局控制
|
11月前
|
人工智能 自然语言处理 并行计算
Maya:基于 LLaVA 开发的多模态小模型,能理解和处理八种语言,适用于低资源环境
Maya 是一个开源的多语言多模态模型,能够处理和理解八种不同语言,包括中文、法语、西班牙语、俄语、印地语、日语、阿拉伯语和英语。该模型基于LLaVA框架,通过指令微调和多语言数据集的预训练,提升了在视觉-语言任务中的表现,特别适用于低资源语言的内容生成和跨文化理解。
457 16
Maya:基于 LLaVA 开发的多模态小模型,能理解和处理八种语言,适用于低资源环境
|
11月前
|
人工智能 自然语言处理 前端开发
CodeArena:在线 LLM 编程竞技场!用于测试不同开源 LLM 的编程能力,实时更新排行榜
CodeArena 是一个在线平台,用于测试和比较不同大型语言模型(LLM)的编程能力。通过实时显示多个 LLM 的代码生成过程和结果,帮助开发者选择适合的 LLM,并推动 LLM 技术的发展。
291 7
CodeArena:在线 LLM 编程竞技场!用于测试不同开源 LLM 的编程能力,实时更新排行榜
|
11月前
|
开发框架 人工智能 安全
Promptic:轻量级 LLM 应用开发框架,提供完善的底层功能,使开发者更专注于构建上层功能
Promptic 是一个轻量级的 LLM 应用开发框架,支持通过一行代码切换不同的 LLM 服务提供商。它提供了类型安全的输出、流式支持、内置对话记忆、错误处理和重试等功能,帮助开发者专注于构建功能,而不是底层的复杂性。
250 6
Promptic:轻量级 LLM 应用开发框架,提供完善的底层功能,使开发者更专注于构建上层功能
|
11月前
|
人工智能 自然语言处理 API
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
谷歌推出的Multimodal Live API是一个支持多模态交互、低延迟实时互动的AI接口,能够处理文本、音频和视频输入,提供自然流畅的对话体验,适用于多种应用场景。
437 3
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
|
11月前
|
搜索推荐 机器人 定位技术
SEO 搜索引擎优化核心名词全解析
本文详细解析了 SEO(搜索引擎优化)中的核心名词,包括关键词、页面标题、元描述、网站地图、反向链接、锚文本、内部链接、页面权重、域权重、搜索引擎机器人、索引、收录、白帽 SEO 和黑帽 SEO。掌握这些术语及其作用,有助于提升网站在搜索引擎中的可见性和排名,实现长期发展。
387 20
|
11月前
|
并行计算 算法 C++
《探索C++在3D重建中的算法与技术要点》
3D重建是计算机视觉的重要技术,广泛应用于多个行业。C++因其高效性和对底层硬件的良好控制,成为实现3D重建算法的首选语言。本文介绍了多视图立体视觉、立体匹配、点云处理与重建、网格重建与优化、纹理映射及CUDA加速等关键技术,详细阐述了各算法的原理和C++实现要点。
279 18
|
11月前
|
设计模式 前端开发 JavaScript
前端必须掌握的设计模式——装饰器模式
装饰器模式是一种结构型设计模式,通过创建新类来包装原始对象,实现在不修改原有结构的前提下扩展新行为。其核心在于“组合”思想,使新功能可“即插即拔”。该模式具有解耦性、灵活性和动态性等特点,广泛应用于类的面向对象编程语言中,如JavaScript的注解和TypeScript的写法。示例中,通过装饰器模式为游戏角色动态添加装备,展示了其强大的扩展性和灵活性。
239 16