数据库抽象-是否过高?


18

在接触了众多数据库抽象层之后,我开始怀疑每个库发明自己的不同范例来访问数据的意义何在。选择一种新的DAL感觉就像是在重新学习一种新的语言,通常我要做的只是说服该层输出我已经写在脑海中的SQL查询。

事实上,这甚至没有涉及可读性:

# Exhibit A:  A typical DAL
rows = db(db.ips_x_users.ip_addr == '127.0.0.1')
    .inner_join(db.ips_x_users.user_id == db.users.id)
    .select(order=(db.ips_x_users.last_seen, 'desc'), limit=10)

# Exhibit B:  Another typical DAL
rows = db.ips_x_users
    .join(db.users, on=db.ips_x_users.user_id == db.users.id)
    .filter(db.ips_x_users.ip_addr == '127.0.0.1')
    .select(sort=~db.ips_x_users, limit=10)

# Exhibit C:  A hypothetical DAL based on standard SQL syntax
rows = db('''SELECT * FROM ips_x_users
             INNER JOIN users ON
                 (ips_x_users.user_id = users.id)
             WHERE ips_x_users.ip_addr = ip
             ORDER BY last_seen DESC LIMIT 10''', ip='127.0.0.1')

标准SQL语法有什么问题?它是为特定目的而创建的,非常适合该目的。也许只有我一个人,但是我比前两个更容易理解片段C。重命名的关键字和语法技巧很可爱,但是IMO刚出现时,对于编码人员而言,它们并没有使检索行变得更加容易。

这似乎有些漫长,但是这里确实一个问题。由于每个DAL似乎都发明了一种用于查询的新DSL,而不仅仅是解析经过验证的SQL,因此使用不同的语法必须有好处,或者我没有意识到标准SQL语法的不足。有人可以指出我在这里俯瞰的景色吗?


2
标准SQL的最大问题是存在许多特定于数据库的查询。外部联接语法与获取“窗口式”查询的过程大相径庭。这就是DAL的开始。现在,如果DAL使用一种标准的SQL变体,并且知道如何处理各种SQL供应商的白痴,我对此表示欢迎。
Berin Loritsch 2011年

Answers:


10

常见SQL使用的最基本问题是,SQL查询是字符串,它们是由另一种语言组成的。这就是SQL注入以及其他漏洞和WTF的来源(您的示例选择得很差,因为您的查询实际上没有任何参数)。

下一个问题实际上是一个必然结果:如果您只在代码中编写了一些SQL,则编译器对此无能为力。诸如列名中的错字之类的错误只会在运行时出现。基本上,这就是为什么您不想在源代码中仅使用查询的字符串表示形式,而是使编译器可以静态分析某些内容以阻止所有Facepalm错误的95%的原因。

当您尝试将关系数据库映射到您的语言语义和编程模型时,就会发生最后一个问题:RDBMS与OOP(或导航数据检索)不能很好地结合在一起。实际上,将这两者结合起来是一个非常糟糕的主意,但这是SQL数据库(即ORM)所有面向对象DAL所要解决的问题。但是所有这些抽象层都注定要泄漏。我认为这基本上就是为什么有很多这样的原因:因为您与他们一起工作,您看到它们有缺陷,所以您着手编写一个正确执行DAL并最终失败的DAL。

因此,虽然问题一和问题二建议使用DAL摆脱SQL,但问题三意味着没有一个简单的解决方案(至少对于OOP),因此总会有各种各样的DAL具有不同的优势和局限性。最后,您所能做的就是仔细选择一些并坚持下去。


3
“ RDBMS与OOP不能很好地结合在一起” – 软件中的所有内容都必须是OO吗?
quant_dev

@quant_dev:不。但是“抽象”层本质上至少是“抽象化”的。同样,提供的代码段也表明我们正在谈论OO代码。
back2dos

我一直以为将SQL嵌入C或其他任何可以想象的最愚蠢的事情。当我不得不做这样的事情时,我创建了一种方法来定义表之间的关系并将其存储在数据库中,然后使用那里的关系在运行时创建SQL来与数据库进行对话。我的C代码只是:“使用此键查找此实体”,“将更改保存到其中”。

9

您忽略了一个明显的事实,即并非所有数据库平台都接受相同的SQL语法,因此在整个应用程序中嵌入SQL语句并不能适用于所有数据库平台。如果您需要支持多个数据库平台,则必须重新考虑大多数(如果不是全部)这些SQL语句。


3
@Note-但是DAL必须具有完整的SQL解析器,并且必须具有自己支持的方言,该方言与任何特定数据库都不同。然后,它将具有当前生成适当的特定于数据库的SQL语句所具有的所有复杂性。例如,您的示例中的LIMIT关键字在MySQL中有效,但在Oracle或SQL Server中无效。
贾斯汀·凯夫

2
现在我们要解决问题了。是什么使非标准的方法名称和运算符重载优于SQL的非标准方言?使用SQL至少会为编码人员提供一个熟悉的基础,以便从中开始学习框架。
请注意-想起名字

3
对自己的@Note:可能是因为编写流畅的API比用SQL的某些方言编写SQL解析器然后将其转换为SQL的其他方言要容易得多。
Dean Harding

1
作为记录,我也更喜欢使用“本机” SQL。我的大多数项目都不需要支持多个数据库,因此这对我来说从来都不是问题。
Dean Harding

3
“您忽略了一个明显的事实,即并非所有数据库平台都接受相同的SQL语法”-是的,但是您多久编写一次针对任何数据库运行的代码?通常,数据库平台是一项重大投资,并且不经常更改。而且,通过针对已知类型的数据库优化查询可以显着提高效率。
quant_dev

5

我觉得SQL经历了10年前指针的相同重大变化。目前正在进行消除SQL手工工作并将其提升到更高抽象级别的尝试。很多年前,指针和手动内存管理也发生了同样的情况。

由于这项工作目前正在进行中,您会发现有很多建议,尝试,放弃和集成的不同方法。我敢肯定,如果您希望自己表现出来的话,我们会在某种通用方法或行业标准之前看到更多。

当您可以在处理应用程序代码时以相同的级别和应用的范式操作数据访问代码时,无疑可以为您提供优势。

简而言之,这就是目标。


4

乔尔10年前写了一篇不错的文章:不要让建筑宇航员吓到你

我认为确实是这样。因为发现了模式,所以我在自己的应用程序中使用了抽象层,因此我很容易这样做。但这是我的DAL,我知道源代码中的每一行=>完全控制。但是我不建议对我的团队/项目以外的任何人使用该框架。

当您使用类似的东西时,重要的是要知道它的实现方式,这意味着您应该花很多时间学习库/工具。如果您没有时间学习它,请不要使用。即使从一开始看起来就很容易。


是的,我过去工作过的公司开始热情地使用Hibernate。然后他们发现了由框架生成的查询有多么令人惊讶(以一种奇怪的方式)。
quant_dev

@quant_dev是的,这就是陷阱-使用Hibernate或JPA开始做简单的事情很容易。
m5ba 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.