Ebean:一款被低估的ORM框架

a60ba9d05cd1cdb2873ec243a7ff77ca.jpeg

ORM框架为什么不香?

对ORM框架的偏见

看了一些MyBaties与Hibernate进行对比的文章。可能是因为一些Hibernate历史原因,国内对于Hibernate普遍存在偏见,我摘抄了几点:

  1. 1. hibernate是全自动,而mybatis是半自动

    hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
  2. 2. sql直接优化上,mybatis要比hibernate方便很多

    由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql
  3. 3. 应用场景

    MyBatis 适合需求多变的互联网项目,例如电商项目、金融类型、旅游类、售票类项目等。 Hibernate 适合需求明确、业务固定的项目,例如 OA 项目、ERP 项目和 CRM 项目等。

也不知道是不是因为这些对Hibernate的偏见,导致大家对ORM框架也普遍存在偏见。

现状是不论大小公司,国内清一色地使用MyBaties。有时,我都不敢说,我喜欢使用ORM框架。

本文并不是一篇为Hibernate洗地的文章,而是介绍另一款比较小众的ORM框架:Ebean。

领域问题分析

介绍Ebean之前,我们需要弄清楚一个问题:为什么会有MyBaties和ORM这些框架?对于这个问题,我们无从下手,那么,我们将问题倒置:如果没有这些框架,会怎么样?

问题倒置的好处是我们立马就有了可下手的方向。我们找到了不使用框架的情况下,Java代码与数据库进行交互的代码:

public static void viewTable(Connection con) throws SQLException {String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";try (Statement stmt = con.createStatement()) {ResultSet rs = stmt.executeQuery(query);while (rs.next()) {String coffeeName = rs.getString("COF_NAME");int supplierID = rs.getInt("SUP_ID");float price = rs.getFloat("PRICE");int sales = rs.getInt("SALES");int total = rs.getInt("TOTAL");}} catch (SQLException e) {JDBCTutorialUtilities.printSQLException(e);}}

这样的代码存在什么问题呢?

  1. 1. 代码不易于维护:你需要知道每个字段在数据库中的类型,才知道该调用ResultSet的哪个方法;

  2. 2. 代码重复:像COF_NAME这样的字段名,在整个代码仓库可能会飘落得到处都是;

  3. 3. 不安全:手工拼装SQL带来的安全问题,不须多言。

以上三个问题,我们称之为ORM领域核心问题。

从目前市面上的解决方案来看,解决这些核心问题的方案,至少需要包含以下三个能力:

  1. 1. 自动映射:在数据库与Java对象之间自动进行字段类型映射,而不是手工进行映射;

  2. 2. 自动生成SQL:根据Java API自动生成SQL,而不是手写;

  3. 3. 自动执行:自动执行,而不是手工直接操作JDBC接口。

MyBaties如何解决核心问题

MyBaties通过Mapper实现自动映射、自动执行。但是并没有实现自动生成SQL,也正是它称之为Mapper的原因。

public interface PersonMapper {@Insert("Insert into person(name) values (#{name})")public Integer save(Person person);@Select("Select personId, name from Person where personId=#{personId}")@Results(value = {@Result(property = "personId", column = "personId"),@Result(property="name", column = "name"),@Result(property = "addresses", javaType = List.class,column = "personId", many=@Many(select = "getAddresses"))})public Person getPersonById(Integer personId);// ...
}

我个人很好奇,为什么MyBatise没有使用JPA规范,而是自己又创造一种注解。

MyBaties另一种通过XML的配置方式配置的,本文就不介绍了。想想当年,Spring也是使用XML进行配置Bean的,现在好像已经没有人这么干了。

说到底,MyBaties也是一个ORM框架。MyBatis-Plus插件的流行程度正好证明了这一点。所以,大家没有必要对ORM框架抱有偏见。:P

JPA小传

在介绍Ebean前,我们回顾一下JPA的历史。

JPA全称:Java Persistent API(Java持久化API)。它只是规范,并不是具体技术,其中Hibernate应该是最出名的实现之一了。Ebean也是具体实现之一。

值得注意的是我们应该可以认定这个规范没有限制我们只能用它将数据持久化到数据库(思路要打开)。即使,我们绝大多数时候,只用它持久化数据到数据库中。

它的版本历史如下:

  • • 2006.5.11: JPA1.0作为JSR220规范的一部分发布。Ebean同年11月发布Bate测试版本;

  • • 2009年:JPA2.0发布;

  • • 2013年和2017年:JPA2.1和JPA2.2分别发布;

  • • 2019年:JPA更名为Jakarta Persistence。

  • • 2020年和2022年:Jakarta Persistence3.0和3.1版本分别发布。

此部分内容来自: https://handwiki.org/wiki/Java_Persistence_API https://en.wikipedia.org/wiki/Jakarta_Persistence

Ebean:一款被低估的ORM框架

Ebean最早于2006年11月13日发布了Bate测试版本。然后v1.0.0版本,在2008年11月24日,由它的作者Rob Bygrave发布到了SourceForge。

后来Ebean迁到了Github。目前最新版本是2023年11月22日。从Github组织来看,Ebean的主要维护人只有:Rob Bygrave。18年的坚持,不得不佩服作者的毅力。

但这也成为我认为Ebean目前最大的问题:如果作者突然有个什么三长两短?社区应该如何应对。即使,它目前有将近100个contributor。

个人在2011左右接触到Play Framework的时候,了解到Ebean。Play框架使用Ebean作为它的JPA实现。当时就被它优秀的设计所吸引。

但是真正让我使用的是:它的设计非常符合我的DDD口味,同时鼓励充血模型的实体。

Ebean是如何实现自动映射的

在上文中,我们已经介绍了ORM领域核心问题:自动映射。这是JPA规范要解决的最重要的问题之一。Ebean实现了JPA规范定义的注解。

用户在字段上加上JPA的注解,然后在真正需要映射的时候,Ebean自动进行映射。以下是定义一个实体Person,它对应的表名是people。实体字段与数据库字段也有相应的映射:

@Entity
@Table(name="people") 
public class Person { @Id@GeneratedValueprivate int id; @Column(name="first_name", length=10)private String firstName; @Column(name="last_name", length=10)private String lastName;

在实体类上中定义Java类与数据库之间的映射关系,最大的好处就是DDL语句和数据库迁移SQL可以被工具自动生成。

假如你在Person类中增加一个email的字段,Ebean的的DDL特性就可以为你生成相应的建表语句。而Ebean的Migration工具就为你生成相应的alert语句。当然,这些语句的执行时机,还是由用户控制。

JPA本身提供了大量注解,Ebean还扩展了一些有用的注解:

  1. 1. @DbJson注解,自动将对象转成JSON进行存储。如果你所使用的数据库支持JSON模式,你会非常喜欢这个注解;有了这个注解,你可能就不需要值对象注解了;

  2. 2. @WhenCreated注解:自动设置对象的创建时间;

  3. 3. @WhenModified注解:自动设置对象的修改时间;

  4. 4. @DbMap注解:自动将Map结构,构建数据库映射到不同的数据类型,如果是Postgre就映射到HSTORE,其它数据库则映射到VARCHAR。

  5. 5. @SoftDelete 软删除注解:当调用实体的delete方法时,只是软删除。只需要在实体中增加一个字段:

@SoftDeleteboolean deleted;

更多相关信息:https://ebean.io/docs/mapping/

Ebean是如何自动生成SQL并执行的

以下我们通过一个实例来展示Ebean相关的能力。

// Database是Ebean与数据库进行交互的主要接口
@Autowired
Database database;
@Test
public void crud() {Person customer = new Person();customer.setFirstName("Jack");customer.setLastName("J");// 这是为了让大家对Ebean的database类有一个感性认知database.save(customer);// 实际应用中,我通常是在Person类中定义一个save方法,并在内容调用database.save(this)。// 最终就是实现这样的调用效果:customer.save()// 批量执行存储。你猜这里应该是生成一条语句,还是多条语句?database.saveAll(customerList);// 根据ID查询对象。Ebean生成相应的select-where语句并执行Customer customerA = database.find(Customer.class, 1);// 当然你也可以只查询其中一个字段的值,Ebean将生成并执行:// select first_name from people where id=1;database.find(Customer.class).select("first_name").where().idEq(1).findSingleAttribute();customerA.setFirstName("Jane");// Ebean会识别出customerA要做的是修改,而不是创建新的记录。所以,生成alert语句并执行。database.save(customerA);// 当然,少不了大家关心的能否执行原生SQLString sql = "select id, first_name from customer where first_name like ?";Customer customer = database.findNative(Customer.class, sql).setParameter("Jo%").findOne();// 另,有时,我们会想念DTO,则可以这么写:List<CustomerDto> beans = database.findDto(CustomerDto.class, "select id, first_name from customer where first_name = :name").setParameter("name", "Rob").findList();// CustomerDto是需要提前定义好的。// 删除记录database.delete(customer);}

至此,已经把Ebean的解决方案介绍完成,由于篇幅有限,还请感兴趣的同学到官网学习。

Ebean的实体类增强技术

在Ebean的官网或者一些网上的文章,你会发现只要实体类继承了Ebean的BaseModel类,都会自动多出save方法以及其它方法。这Lombok与类似,只要加一个@Setter注解,类中就自动出多了相应的setter方法。

又或者,你会看到:

Person contact = new QContact().firstName.equalTo("rob").findOne();

QContact类是由Ebean生成的(在实体类前加一个Q字母代表查询类),方便用户使用链式调用来查询自己想要数据。而不是需要像database.find(Customer.class).select("first_name")这样手工写字段名。

发生以上的魔法是因为Ebean使用了增强(Enhancement)技术。这项技术必须嵌入到我们的IDE和构建工具中,否则相关代码的编译都不可能通过。

Enhancement技术虽然让我们少写代码,但是我们也要认清这门技术所带来的成本:它使我们的开发环境强依赖相应的插件。比如Maven必须要安装它的插件才能构建通过、IDE必须安装插件才能正常写代码。

幸运的是,我们可以选择不使用它的编译时生成的代码。IDE也就不需要安装相应的插件了。

我个人宁愿自己在实体中手写save方法,也不使用这项技术生成。另一个重要的考虑因素是:我不希望领域实体类依赖于具体实现技术。

然而,运行时,还是必须加上agent,即-javaagent:<路径>/ebean-agent.jar,以便Ebean对实体进行脏检查和懒加载支持。

使用经验

以下是一些个人的使用经验,仅供参考:

  1. 1. JPA的所有API,并不是每一个都必须用到。比如字段上的@Basic(fetch=FetchType.LAZY)懒式加载,我就不建议使用。因为在实际工作中,你不能确保每个人都理解懒式加载的应用场景;比如它的JPQL,我们完全没有必要又另学一种SQL,再者Java API的调用方式才应该是推荐;

  2. 2. 使用Java配置类对Ebean进行配置,而不是使用官网介绍properties配置。只有这样才足够灵活应对将来的多数据源需求;

  3. 3. 在实体类中不要直接使用Ebean的技术,而是在实体类中调用repository接口,再由repository的实现调到Ebean。

如果各位读者想看更多的Ebean如何实现DDD repository的文章,请点赞并转发。

关于DDD的文章:

  • 我是如何将同事的代码改成DDD风格的

  • 这十年,我所经历的领域驱动设计(DDD)

  • 领域驱动设计(DDD)下没有POJO

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

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

相关文章

如何让软文真正起效?媒介盒子为你解答

在如今这个互联网大环境下&#xff0c;想要写出有价值的软文去“忽悠”用户其实是不简单的&#xff0c;那我们应该怎么做才能让软文真正起效呢&#xff1f;媒介盒子为你解答。 一、软文写作前 1.了解平台特性 每个平台都有自己的定位。有的定位于以分享专业知识为主&#xff…

某和医院招采系统web端数据爬取, 逆向js

目标网址:https://zbcg.sznsyy.cn/homeNotice 测试时间: 2024-01-03 1 老规矩,打开Chrome无痕浏览,打开链接,监测网络,通过刷新以及上下翻页可以猜测出数据的请求是通过接口frontPageAnnouncementList获取的,查看返回可以看出来数据大概率是经过aes加密的,如图: 通过查看该请…

014、枚举与模式匹配

枚举类型&#xff0c;通常也被简称为枚举&#xff0c;它允许我们列举所有可能的值来定义一个类型。在本篇文章中&#xff0c;我们首先会定义并使用一个枚举&#xff0c;以向你展示枚举是如何连同数据来一起编码信息的。 接着&#xff0c;我们会讨论一个特别有用的枚举&#xff…

提升设计效率:全面了解如何使用Figma插件

Figma组件库包括颜色、字体、图标、按钮、阴影、圆角、间距等。当Figma组件库的样式和Figma组件达到一定数量时&#xff0c;将难以维护&#xff0c;设计和开发的对接成本将大大提高。Figma可以在同一母版下单独设置样式&#xff0c;而不影响与母版之前的关系&#xff0c;这是Sk…

9.java——(杂例)组合,代理,向上转型static,fianl,关键字(有道云笔记复制粘贴,大家整体性的把握)

组合——内部有类&#xff08;心中有对象&#xff01;&#xff01;&#xff01;&#xff09;&#xff08;足球 和足球运动员梅西和脚下的足球一样&#xff09; has和is的区别&#xff0c;has是组合&#xff0c;是有&#xff0c;持有的意思&#xff1b;is是继承&#xff0c;是…

C++八股学习心得.3

1.C 数组 C 支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素&#xff0c;最高的地址对应最后一个…

实时计算大作业kafka+zookeeper+storm+dataV

第一章 总体需求 1.1.课题背景 近年来&#xff0c;大数据称为热门词汇&#xff0c;大数据分析随着互联网技术的发展愈加深入电商营销之 中&#xff0c;越来越多的电商企业利用大数据分析技术&#xff0c;利用信息化对产业发展营销方向进行确定&#xff0c; 对电子商务行…

双碳管理系统任务需求分析(第10套)

需求规格说明书 一、引言 &#xff08;一&#xff09;项目背景 编写本需求规格说明书的目的是为了详细呈现碳足迹产品需求和系统的功能描述&#xff0c;以进一步定制应用软件系统开发的细节问题&#xff0c;便于与项目开发协调工作。本文档面向的读者主要是项目委托单位的管…

git rebase(变基)应用场景

文章目录 git rebase(变基)应用场景1.git rebase -i HEAD~3 git rebase(变基)应用场景 使得提交记录变得简洁 现在我们模拟我们有多次提交记录&#xff0c;本地仓库有三条提交 整合成一条提交记录 1.git rebase -i HEAD~3 提交记录合并 HEAD~3合并三条记录 执行之后 然后把…

事实就是这么残酷,分享一个案例投资者是怎么一步步失败

都说交易市场要学会斗智斗勇&#xff0c;但fpmarkets澳福提醒交易者要始终记住&#xff0c;买的没有卖的精&#xff0c;下面就分享一个案例&#xff0c;让各位投资者知道现实就是这么残酷&#xff0c;一些无良的资本是怎么一步步让投资者失败的。 当在整个交易市场中渐渐地&am…

清风数学建模笔记-时间序列分析

内容&#xff1a;时间预测分析 一.时间序列 1.时点时间序列 2.时期时间序列&#xff1a;可相加 二.时间趋势分解 1.季节趋势 拓展&#xff1a;百度指数&#xff1a; 2.循环变动趋势&#xff08;和季节很像但是是以年为单位&#xff09; 3.不规则变动趋势&#xff08;像扰…

《深入理解C++11:C++11新特性解析与应用》笔记八

第八章 融入实际应用 8.1 对齐支持 8.1.1 数据对齐 c可以通过sizeof查询数据的长度&#xff0c;但是没有对对齐方式有关的查询或者设定进行标准化。c11标准定义的alignof函数可以查看数据的对齐方式。 现在的计算机通常会支持许多向量指令&#xff0c;4组8字节的浮点数据&a…

离线Vscode 安装完成后 添加到右键菜单

复制下面代码&#xff0c;修改文件后缀名为&#xff1a;reg Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\*\shell\VSCode] "Open with Code" "Icon""D:\\_Porgram_IT\\VsCode\\Code.exe"[HKEY_CLASSES_ROOT\*\shell\VSCode\comman…

AI:110-基于深度学习的药物分子结构生成与预测

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

填充点云孔洞(较大的洞)halcon算法

前言 很多时候,一些小洞可以通过平滑算法,或者三角化算法的参数调整,即可对较小的孔洞进行填充,但是较大的洞却很难通过上面的算法进行填充。 下面介绍一种填充孔洞的思路: 步骤一:对点云进行滤波处理,找到孔洞所在平面 本文为了更直观的进行讲解,去掉了去除噪声和…

数读中国这十年:研发经费超3万亿元 创新引领显成效

摘要&#xff1a;本文转载自新华社。 新华社北京12月22日电 题&#xff1a;研发经费超3万亿元 创新引领显成效 新华社记者 陈炜伟、潘德鑫 这是2023年6月11日在青海省海西蒙古族藏族自治州格尔木市拍摄的一座光热电站&#xff08;无人机照片&#xff09;。新华社记者 张宏…

Linux高级玩家必备sos_report-尚文网络xUP楠哥

进Q群11372462领取专属报名福利! # 什么是sos sos 是红帽技术支持工程师在执行任务时的常见起点分析 RHEL 系统的服务请求。 该实用程序提供了一种标准化的方式来收集红帽支持工程师可以在整个调查过程中参考的诊断信息支持案例中报告的问题。 使用 sos 报告实用程序有助于确…

亚马逊站内广告位置在哪设置?怎么设置广告位置?-站斧浏览器

亚马逊站内广告位置在哪设置&#xff1f; 亚马逊提供了多种广告类型&#xff0c;包括&#xff1a; Sponsored Products&#xff08;赞助产品&#xff09;&#xff1a;在搜索结果和商品详情页中展示。 Sponsored Brands&#xff08;赞助品牌&#xff09;&#xff1a;在搜索结…

Fast R-CNN

Fast R-CNN算法流程 对比与R-CNN其在第二步时并没有将所有的候选区域进行逐个的CNN特征提取&#xff0c;而是直接将整个图片进行一次CNN特征提取&#xff0c;让后再将候选区映射到feature map上。可想而知速度得到了提升。这里的ROI pooling层缩放到7x7就是将候选区域对应的特征…

通过聚道云软件连接器实现销帮帮软件与i人事软件的智能对接

客户介绍 某软件行业公司是一家专业从事软件技术服务、软件开发、应用解决方案、业务流程优化、专业服务的高科技企业。公司拥有一支经验丰富、技术精湛的服务团队&#xff0c;具备多年的软件开发和应用解决方案经验。他们不断追求技术的创新和进步&#xff0c;以满足客户不断…