使用ORM还是普通SQL?

对于我开发的一些应用程序(后来渐渐忘记了),我一直在编写纯SQL,主要用于MySQL。虽然我在python中使用过orm,比如SQLAlchemy,但我并没有坚持太久。通常是文档或复杂性(从我的角度来看)阻碍了我。

我是这样认为的:为了可移植性,使用ORM,如果只使用一种类型的数据库,则使用纯SQL。在开发需要数据库支持的应用程序时,我真的在寻找关于何时使用ORM或SQL的建议。

考虑到这一点,使用轻量级包装器来处理数据库不一致要比使用ORM好得多。

121068 次浏览

任何值得尊敬的设计都需要对数据库进行一些抽象,以处理阻抗不匹配。但是我认为最简单的第一步(对于大多数情况来说已经足够了)应该是DAL,而不是重量级的ORM。你唯一的选择并不是那些极端的选择。


编辑回复一个要求我描述如何区分DAL和ORM的评论:

DAL是您自己编写的,可能从简单地封装一个表并将其字段映射到属性的类开始。ORM是不需要为从dbms模式的其他属性推断出的抽象机制而编写的代码,主要是pk和fk。(这是您发现自动抽象是否开始出现漏洞的地方。我更喜欢有意地告知他们,但这可能只是我的个人偏好)。

ORM不仅仅是可移植性(就这一点而言,即使使用ORM也很难实现可移植性)。当ORM工具将您从编写模板SQL查询(通过PK或谓词、插入、更新和删除进行选择)中解放出来,并让您专注于问题域时,它基本上为您提供了持久存储之上的抽象层。

我开发的一个应用是用python写的IRC机器人。它使用的模块在单独的线程中运行,但我还没有找到一种方法来处理使用sqlite时的线程。不过,这可能是一个单独的问题。

我真的应该把题目而且和实际问题都改写一下。我从来没有在任何语言中使用过DAL。

作为一个经常使用JPA (Java Persistence API,基本上是Java/J2EE/EJB的标准化ORM API)(包括Hibernate、EclipseLink、Toplink、OpenJPA等)的人,我将分享一些我的观察结果。

  1. orm并不快。它们可以是足够的,大多数时候足够是可以的,但在高容量低延迟的环境中,它们是不可取的;
  2. 在像Java和c#这样的通用编程语言中,你需要大量的魔法才能让它们工作(例如Java中的加载时编织,仪器等);
  3. 当使用ORM时,你会惊奇地发现,为了让ORM生成性能良好的SQL,你花费了大量的时间来调整XML和/或注释/属性,而不是进一步脱离SQL(这似乎是我们的意图);
  4. 对于复杂的查询,确实没有替代品。就像在JPA中,有一些查询根本不可能在原始SQL中,当你不得不在JPA中使用原始SQL时,它不是很漂亮(c# /。Net至少有动态类型——var——这比Object数组好得多);
  5. 有很多“陷阱”。使用orm时。这包括非预期的或意外的行为,事实上,您必须构建对数据库进行SQL更新的功能(通过在JPA中使用refresh()或类似的方法,因为JPA默认情况下缓存所有内容,因此它不会捕获直接的数据库更新——运行直接的SQL更新是一种常见的生产支持活动);
  6. 对象-关系不匹配总是会导致问题。对于任何这样的问题,都需要在抽象的复杂性和完整性之间进行权衡。有时,我觉得JPA走得太远了,并且遇到了收益递减的实际规律,在这种情况下,复杂性所受到的打击并不能被抽象所证明。

还有一个问题需要更多的解释。

Web应用程序的传统模型是有一个持久层和一个表示层(中间可能有一个服务或其他层,但这是本文中重要的两个层)。orm强制从持久层到表示层(即实体)使用刚性视图。

对更原始SQL方法的批评之一是,您最终会得到所有这些仅由一个查询使用的vo(值对象)或dto(数据传输对象)。这被吹捧为orm的一个优势,因为你摆脱了这一点。

问题是,这些问题不会随着orm而消失,它们只会上升到表示层。不为查询创建VOs/ dto,而是创建自定义表示对象,通常为每个视图创建一个。这怎么更好呢?恕我直言,它不是。

我已经在ORM或SQL:我们已经做到了吗?中写过这个。

最近我选择的持久化技术(在Java中)是ibatis。它是一个非常薄的SQL包装器,可以完成JPA所能做的90%以上的工作(它甚至可以进行惰性加载关系,尽管它没有良好的文档),但开销要小得多(就复杂性和实际代码而言)。

这是在去年我编写的GWT应用程序中出现的。在服务实现中,从EclipseLink到表示对象的大量转换。如果我们使用ibatis,那么用ibatis创建适当的对象,然后在堆栈中上下传递它们就会简单得多。一些纯粹主义者可能会认为这是坏的™。也许是这样(理论上),但我告诉你:它会带来更简单的代码、更简单的堆栈和更高的生产力。

orm有一些不错的特性。它们可以处理将数据库列复制到对象字段的大量繁琐工作。它们通常处理将语言的日期和时间类型转换为适当的数据库类型。它们通常通过实例化嵌套对象来非常优雅地处理一对多关系。我发现,如果在设计数据库时考虑到ORM的优点和缺点,就可以节省大量数据进出数据库的工作。(如果需要映射多态性和多对多关系,则需要知道它如何处理这些关系。正是这两个领域提供了大部分的“阻抗不匹配”,使一些人称ORM为“计算机科学的越南”。)

对于事务性应用程序,即您发出请求,获取一些对象,遍历它们以获得一些数据并在Web页面上呈现,性能损失很小,并且在许多情况下ORM可以更快,因为它将缓存以前见过的对象,否则将多次查询数据库。

对于报告量大的应用程序,或者每个请求都要处理大量的数据库行,ORM税要重得多,它们所做的缓存变成了一个巨大的、无用的内存占用负担。在这种情况下,可以使用简单的SQL映射(LinQ或iBatis)或在瘦DAL中手工编写SQL查询。

我发现,对于任何大型应用程序,您都会发现自己同时使用这两种方法。(ORM用于直接的CRUD, SQL/thin DAL用于报告)。

在现代软件开发场景中,是否使用框架是非常常见的难题。

重要的是要理解每个框架或方法都有其优点和缺点——例如,根据我们的经验,我们发现ORM在处理事务时很有用,即插入/更新/删除操作——但当涉及到获取具有复杂结果的数据时,评估ORM工具的性能和有效性就变得重要了。

同样重要的是要理解,选择一个框架或方法并在其中实现所有内容并不是强制性的。我们的意思是,我们可以混合使用ORM和本地查询语言。许多ORM框架在本地SQL中为插件提供扩展点。我们应该尽量不要过度使用一个框架或方法。我们可以结合某些框架或方法,得出适当的解决方案。

当涉及到高并发性的插入、更新、删除和版本控制时,可以使用ORM,还可以使用Native SQL生成报告和长清单

使我的ORM使用真正成功的关键是代码生成。就代码性能而言,我同意ORM路由不是最快的。但是,当您拥有一个中型到大型的团队时,DB正在迅速变化,从DB中重新生成类和映射作为构建过程的一部分的能力是值得注意的,特别是当您使用CI时。所以你的代码可能不是最快的,但你的代码会-我知道我在大多数项目中会采用哪种。

我的建议是在模式仍处于流动状态时使用ORM进行开发,使用分析来发现瓶颈,然后使用原始Sql优化那些需要它的区域。

另一个想法是,如果使用得当,Hibernate内建的缓存通常可以大大提高性能。不再需要返回DB读取引用数据。

没有“一刀切”的解决方案,对于“我是否应该使用an或/m”这个问题也是如此。”。

我会说:如果你必须写一个非常“数据”的应用程序/工具,没有太多的其他逻辑,那么我会使用纯SQL,因为SQL是这类应用程序的领域特定语言。

另一方面,如果我要编写一个包含大量“领域”逻辑的业务/企业应用程序,那么我将编写一个富类模型,它可以在代码中表达这个领域。在这种情况下,OR/M映射器可能会非常有用,因为它可以从您手中省去大量管道代码。

我用纯SQL表示Reads,用ORM表示反刍的食物

性能是我一直关注的问题,尤其是在web应用程序中,但同时也关注代码的可维护性和可读性。为了解决这些问题,我写了SqlBuilder

使用一个可以工作就像 SQL的ORM,但提供编译时检查和类型安全。就像我最喜欢的:数据知识对象(披露:我写的)

例如:

for (Bug bug : Bug.ALL.limit(100)) {
int id = bug.getId();
String title = bug.getTitle();
System.out.println(id +" "+ title);
}

完全流。易于设置(不需要定义映射-读取现有模式)。支持连接、事务、内部查询、聚合等。几乎可以用SQL做任何事情。从庞大的数据集(金融时间序列)一直到琐碎的数据集(Android),这一点都得到了证明。

我知道这个问题很老了,但我想我应该在这里发布一个答案,以防有人像我一样遇到这个问题。orm已经走过了很长的路。其中一些实际上为您提供了两全其美的服务:提高开发效率并保持性能。

看看SQL Data (http://sqldata.codeplex.com)。它是c#的一个轻量级ORM,涵盖了所有基础。

供参考,我是SQL数据的作者。

我想和大家一起回答:“我们有一个中间立场!”

对于应用程序程序员来说,SQL是您可能想要控制的东西和您几乎肯定不想费心控制的东西的混合体。

我一直想要的是一个层(称之为DAL、ORM或microorm,我不介意哪个),它将负责完全可预测的决策(如何拼写SQL关键字,括号放在哪里,何时创建列别名,为一个包含两个浮点数和一个int的类创建哪些列……),同时让我负责SQL的高级方面,即如何安排join、服务器端计算、DISTINCTs、GROUP by、标量子查询等。

所以我写了一些这样的东西:http://quince-lib.com/

这是针对c++的:我不知道这是否是你正在使用的语言,但同样的,看看这个“中间地带”的样子可能会很有趣。