封装SQL平台之间差异的策略?

时间:2012-07-18 12:00:18

标签: java sql encapsulation robustness

我正在努力加速一些慢速操作,一个案例是表格中的父子关系树。目前系统在SQLServer上运行,经过一些研究后我发现,通过公用表表达式,可以将多个查询压缩成一个。

到目前为止一切都那么好,但语法是特定于SQLServer并且与(例如)Oracle做同样的事情需要完全不同的语法。

如何构建系统以便将来适应其他RDBMS可以做些什么?我的主要关注点是:

  • SQL语句遍布代码,一个RDBMS中的 one 语句可能会在另一个RDBMS中使用多个语句,因此即使程序逻辑也可能需要更改。
  • 即使可以在一个RDBMS中很好地封装的东西(我使用存储的函数来隐藏数据库中的一些复杂性)也会在不同的数据库中产生微妙的差异,或根本不可用。

到目前为止,我觉得超越最简单的SQL语句的所有内容似乎总是需要供应商特定的扩展,这使得无法将差异隐藏在几个类/存储的SQL中(确定在可以使用已经构建了大部分抽象的框架。但这也排除了DB的许多更有用的功能。)

可以使用哪些策略来至少缓解供应商差异的痛苦?我知道这是一个非常广泛的问题,没有万灵药的答案。但是我希望有一些指针和模式来减轻数据库对应用程序的影响。

编辑:实现语言是Java,简单地使用ORM(例如Hibernate)并不是我想要的(或多或少需要重写~50%的代码库)。

EDIT2:我主要寻找以尽可能兼容的方式将细节推送到数据库的可能性,理想情况下我希望java部分使用的SQL对于所有平台都是相同的(或者由于语法上的差异,只需要非常轻微的变化)。对于我给出的CTE示例,我目前将其推送到存储函数中,希望当需要移植时,功能也可以在函数中重现。

EDIT3:目前我没有迫切需要来支持其他RDBM。如果它只适用于SQLServer,没有人会责怪我。但是在可能的情况下,我希望避免将java代码与特定数据库供应商联系起来。

EDIT4:一些背景 - 目前的工作是为系统添加功能 - 它没有设计或计划的功能。这些要求从商务人员那里逐渐涓涓细流,难以提前计划。虽然每个要求本身并不是非常难以解决,但我担心我们会积累一大堆标记在无法移植的东西上,而不会详细地查询每个查询。由于SQLServer本身也在每个主要的新版本中引入了各种不兼容性,我担心即使转换到新的SQLServer也可能成为未来的主要障碍(我们过去曾做过2005年到2008年的一次升级 - 那个去了顺利完成我正在维护的东西,但它已经导致我们的一个供应商出现了一些问题。)

4 个答案:

答案 0 :(得分:0)

您没有指定yuo正在使用的应用程序平台。但我认为你使用的是.Net或Java。您的第一道防线是在应用程序的SQL语句中使用ODBC或JDBC转义序列,并将此方法无法处理的任何内容推送到存储过程中。

如果您拥有对应用程序进行更彻底重构的许可,则应考虑切换到应用程序平台的ORM库。

编辑:我看到你编辑了你的问题,澄清你正在使用Java并且不能选择切换到ORM库。很久以前,我正在为大型企业客户开发产品。每个客户都有自己的标准参考架构,因此我们必须适应Oracle,Microsoft SQL Server和UDB / DB2。我们可能已经支持其他平台,但是一些细节在10到12年后确实会变得模糊。我们通过虔诚地使用JDBC转义来实现时间常量,函数和存储的函数调用以及将更敏感的操作推送到特定于数据库的存储过程中。所以我可以根据我的经验告诉你这种方法是有效的。目前,通过一系列收购,该产品是Oracle中间件产品组合的一部分,因此我甚至不知道它是否支持Oracle以外的任何产品。

我的另一个经验是关于大数据仓库项目。在这种情况下,我们如此大量使用特定于Oracle的功能,转移到另一个数据库平台根本不是一个选项。

因此,我的建议是评估是否使用特定于SQL Server的功能是您的应用程序所固有的。如果是,你应该接受,如果没有重大的重写,移动到另一个平台是不可取的。虽然如果不是,请查看是否可以通过使用JDBC转义来改进SQL的sprincled。

答案 1 :(得分:0)

鉴于您使用遗留代码,我会选择一个接口,最初是一个实现,为每个与数据库相关的函数添加方法,例如SaveOrder,需要一个简单的类,例如订购:),或推送数据集。随你进行更多的东西,直到所有的sql都在实现中,并且使用它的所有东西都通过接口。

然后,当您想要实现到另一个数据库,或者可能是其他持久层(如NoSQL,Xml或ORM)时,您知道自己需要做什么,并且还要进行一系列单元测试。

答案 2 :(得分:0)

您可以考虑使用MyBatis框架。 MyBatis将SQL查询和结果集映射到Java对象,它还支持DB特定的查询生成。放入现有应用程序非常轻量级,它可能会大大减少您的总代码行数。请查看the section on Multi-db vendor support in their documentation以获取演示该功能的快速示例映射文件。

答案 3 :(得分:0)

  1. 远离ORM。他们确实在项目中有自己的目的,但是如果你只想要数据库独立,那就像购买一般工厂工厂,只需要一把锤子和一些钉子。

  2. 将数据访问层隔离在一组接口后面。您的代码库中的任何内容都不应该依赖于数据库,而是这些接口的实现。因此,在这些实现之外的任何类都不应该在类路径中使用'jdbc','jpa'或'hibernate'访问任何内容。您可以考虑使用JDepend或DependencyFinder为其编写实际测试。

  3. 让您当前的数据库访问实现这些接口。

  4. 针对实际数据库运行自动化测试,并准备针对一组不同的数据库运行。

  5. 当您必须支持第二个数据库时,请修改您的测试以针对这两个数据库运行。使接口实现成为原始实现的副本,然后修复失败的测试。

  6. 现在看看你的两个实现,找到值得提取和重构你的代码的东西。

  7. 如果您尝试在链中进一步向上移动第6步,则会遇到YAGNI和WrongAbstractionException的错误情况。

    如果您决定使用任何类型的ORM或其他数据库访问技术,则适用相同的规则。