Java编程 - SQL语句应该存储在哪里?

时间:2009-11-02 15:24:32

标签: java sql

符合JDBC的应用程序应该在哪里存储其SQL语句?为什么?

到目前为止,我设法识别出这些选项:

  • 在业务对象中硬编码
  • 嵌入SQLJ条款
  • 封装在不同的类别中,例如 Data Access Objects
  • 元数据驱动(解耦对象 来自数据模式的模式 - 描述它们之间的映射 元数据)
  • 外部文件(例如属性或 资源文件)
  • 存储过程

每个人的“优点”和“缺点”是什么?

SQL代码应该被视为“代码”还是“元数据”?

存储过程是否应仅用于性能优化,还是数据库结构的合法抽象?

性能是决定的关键因素吗?那么vendor lock-in呢?

什么是更好的 - 松耦合或紧耦合?为什么?

编辑:谢谢大家的答案 - 这里有一个摘要:

元数据驱动,即对象关系映射(ORM)

优点:

  • 非常抽象 - 数据库服务器可以 切换而无需改变 模特
  • 广泛传播 - 实际上是标准
  • 减少所需的SQL数量
  • 可以将SQL存储在资源文件中
  • 表现(通常)可以接受
  • 元数据驱动方法
  • (数据库)供应商独立性

缺点:

  • 隐藏SQL和真正的开发人员 意图
  • SQL很难被审核/更改 由DBA
  • 奇怪的可能仍然需要SQL 例
  • 可以强制使用专有 查询语言例如HQL
  • 不适合优化 (抽象)
  • 缺乏参照完整性
  • 替代缺乏SQL知识 或者对数据库中的代码缺乏关注
  • 绝不匹配原生数据库 表现(即使它接近)
  • 模型代码非常紧密 数据库模型

在DAO图层中硬编码/封装

优点:

  • SQL保存在对象中 访问数据(封装)
  • SQL易于编写(速度快 发展)
  • SQL很容易追踪 需要更改
  • 简单的解决方案(没有凌乱 体系结构)

缺点:

  • DBA
  • 无法查看/更改SQL
  • SQL很可能成为特定于数据库的
  • SQL可能难以维护

存储过程

优点:

  • SQL保存在数据库中(靠近 数据)
  • 解析,编译和优化SQL 由DBMS
  • SQL很容易让DBA审核/更改
  • 减少网络流量
  • 提高安全性

缺点:

  • SQL与数据库绑定(供应商 锁定在)
  • SQL代码难以维护

外部文件(例如属性或资源文件)

赞成

  • 可以在不需要的情况下更改SQL 重建应用程序
  • 将SQL逻辑与 应用程序业务逻辑
  • 所有SQL的中央存储库 陈述 - 更易于维护
  • 易于理解

缺点:

  • SQL代码可能无法维护
  • 更难检查SQL代码 (语法)错误

嵌入在SQLJ子句中

优点:

  • 更好的语法检查

缺点:

  • 与Java密切相关
  • 性能低于JDBC
  • 缺乏动态查询
  • 不那么受欢迎

15 个答案:

答案 0 :(得分:28)

通常,应用程序在大小和/或可重用性方面增长得越多,就越需要对SQL语句进行外部化/抽象化。

硬编码(作为静态最终常量)是第一步。 下一步是存储在文件(properties / xml文件)中。 元数据驱动(由像Hibernate / JPA这样的ORM完成)是最后一步。

Hardcoded的缺点是您的代码很可能成为特定于DB的,并且您需要在每次更改时重写/重建/重新分配。优点是你有一个地方。

存储在文件中的缺点是,当应用程序增长时,它可能变得不可维护。优点是您不需要重写/重建应用程序,除非您需要添加额外的DAO方法。

元数据驱动的缺点是模型代码与数据库模型非常紧密。对于数据库模型中的每个更改,您都需要重写/重新构建/重新分发代码。优点是它非常抽象,您可以轻松地从数据库服务器切换而无需更改您的模型(但现在问问自己:公司多久更换一次数据库服务器?可能至少每三年一次,不是'是吗?)。

我不会将存储过程称为“好”解决方案。它们有着完全不同的目的。即使您的代码依赖于所使用的数据库/配置。

答案 1 :(得分:21)

我不知道这是否是最佳的,但根据我的经验,他们最终在DAO层中硬编码(即字符串文字)。

答案 2 :(得分:11)

我不认为有人会给你你想要的职业分析,因为这是一个相当大的问题。所以这就是我过去使用的,以及我将来会使用的内容。

我用来在DAL中使用硬编码的SQL。我认为这很好,直到DBA想要使用SQL。然后你必须把它挖出来,格式化并将其解雇给DBA。谁会嘲笑它并取而代之。但是如果没有好的问号,或者问题标记的顺序错误,请将其粘贴在Java代码中。

我们也使用了ORM,虽然这对开发人员来说非常好,但我们的DBA讨厌它,因为没有SQL可供他们嘲笑。我们还使用了一个奇怪的ORM(来自第三方供应商的定制ORM),它习惯于杀死数据库。我从那时起就使用过JPA并且很棒,但是通过DBA获得任何复杂的东西都是一场艰苦的战斗。

我们现在使用存储过程(使用硬编码的调用语句)。现在每个人都会抱怨的第一件事就是你与数据库联系在一起。你是。但是你多久更换一次数据库?我知道一个事实,我们甚至无法尝试它,依赖于它的其他代码的数量加上重新训练我们的DBA以及迁移数据。这将是一个非常昂贵的操作。但是,如果在你的世界中需要一点点改变数据库,则可能需要SP。

展望未来我想使用存储过程和代码生成工具从Oracle包创建Java类。

编辑2013-01-31 :几年后和DBA以后我们现在使用Hibernate,只在绝对需要时才转到SQL(在DB中存储过程)。我认为这是最好的解决方案。数据库中99%的时间不需要担心SQL,而他们这样做的1%就是他们已经习惯的地方。

答案 3 :(得分:10)

通过使用ORM(例如hibernate),您希望无需担心 no SQL语句。性能通常是可以接受的,您也可以获得供应商独立性。

答案 4 :(得分:10)

  

SQL代码应该被视为“代码”还是“元数据”?

代码。

  

存储过程是否应仅用于性能优化,还是数据库结构的合法抽象?

存储过程允许重用,包括其他存储过程内部。这意味着您可以前往数据库和数据库。让它执行支持指令 - 最少的流量是理想的。 ORM或者sproc,电线上的时间到db&回来是你无法回收的东西。

由于它的抽象,ORM不适合优化。 IME,ORM也意味着缺乏参考完整性 - 使数据库难以报告。现在已经增加了以复杂性保存的内容,以便能够以可行的方式获取数据。

  

性能是决定的关键因素吗?供应商锁定怎么办?

不,简单就是。供应商锁定也发生在数据库中 - SQL相对标准化,但仍有供应商特定的处理方式。

答案 5 :(得分:9)

对java世界中供应商锁定的恐惧很有意思。

我希望您没有为Oracle Enterprise支付$ 50000 pr CPU,然后只使用最小公分母才能在任何时候切换到Mysql。正如任何优秀的DBA会告诉你的那样,不同的大名称数据库之间存在细微差别,特别是关于锁定模型以及它们如何实现一致性。

因此,不要仅根据供应商不可知SQL的原则来决定如何实现SQL调用 - 这样做有真正的(商业)原因。

答案 6 :(得分:6)

存储过程中的SQL由数据库系统优化并为速度编译 - 这是它的自然之家。数据库系统理解SQL,由数据库系统解析。如果可以,请将SQL保留在数据库中;将它包装在存储过程或函数或数据库系统提供的任何逻辑单元中,并使用您或任何其他人提到的任何工具对其进行简单调用。

为什么要在db之外存储数据库系统的SQL代码?通常是为了发展速度。为什么要使用ORM映射? - 有人说ORM映射提供了跨不同数据库系统的兼容性;但是在现实世界中很少有应用程序在构建它时特别是当它开始使用复制等高级功能时从数据库平台转移,并且在极少数情况下确实会发生数据库系统被换出的情况,有些工作是有保证的。我相信ORM的一个缺点是它经常替代缺乏SQL知识或缺乏对db中代码的关注。此外,ORM永远不会匹配本机数据库性能,即使它接近。

我站在将SQL代码保存在数据库中并通过您希望使用的任何API或接口对其进行简单调用的方面。通过将这些调用放在抽象类或OO接口(由方法表示)后面,抽象出数据库调用的点,所以如果你换一种新的数据源,它将与业务层无缝连接。

答案 7 :(得分:5)

你问的唯一一个有明确答案的问题是“是SQL代码还是元数据?”它绝对是代码,因此应该保存在某种源代码控制中,并且有一个系统可以轻松更新到最新版本并在时回滚而不是出现问题。

我已经在应用程序中看到了三种执行SQL的方法,每种方法都有其优点和缺点。利弊。没有最好的方法,但最好的方法就是选择一个适用于您的应用程序并坚持下去的方法。

  • ORM - 这会减少您需要编写的SQL数量,并为您处理大量细节。您将需要执行一些自定义SQL。确保你有一个优雅地处理这个问题的ORM。
  • 数据访问对象 - 将SQL保留在访问数据的对象中。这封装了您的数据库并使其成为所以应用程序的其余部分不需要知道底层数据库结构,只需要了解这些对象的接口。
  • 存储过程 - 这会将您的所有SQL保存在数据库中,使您的DBA可以轻松了解正在发生的事情。您需要做的就是让您的代码调用存储过程

答案 8 :(得分:4)

我们碰巧使用iBatis SQL映射器,它比Hibernate之类的ORM更接近金属。在iBatis中,您将SQL语句放入资源文件(XML)中,这些文件需要位于类路径中。

如果添加@ ocdecio的ORM选项,您的方法列表似乎相当全面。我会说使用ORM并使用SQL映射器和资源文件是两种最好的方法。我会从SQLJ中明确指出,SQLJ没有得到太多的关注,并且与Java过于紧密地联系在一起。还要远离存储过程,因为它们将您绑定到特定的数据库供应商(存储过程几乎不存在标准)。

答案 9 :(得分:4)

像我们大多数人一样,我已经看到了整个gammut,但我们需要将SQL视为一流的语言。我甚至看到存储在DB中的SQL被拉下来然后执行备份。

我见过的最成功的系统采用存储过程,函数和视图。

存储过程将SQL文本保留在数据库中,并允许那些部署和自定义(这需要大量适当的设计来支持它)进行相对立即的更改。

出于同样的原因,所有投影都应该通过视图和简单选择,所有投影逻辑都应该包含在视图中。

答案 10 :(得分:2)

我建议使用具有工厂布局的DAO。所以你需要的示例对象是:

public class CoolBusinessObject
public class DAOFactory.java
public implementation CoolBusinessOjectDAO
public class CoolBusinessOjectDAOOracleImpl implements CoolBusinessOjectDAO

此样式对数据交互进行分层,因此,如果切换数据库或转移到ORM技术,则只需更改一层代码。

答案 11 :(得分:2)

这三者之间并没有实质性的差异:

  1. 在业务对象中硬编码
  2. 嵌入SQLJ条款
  3. 封装在不同的类别中,例如Data Access Objects
  4. 我假设您要将SQL代码以字符串形式直接嵌入到Java代码中。虽然1和3可能直接使用JDBC(或某些工具,如Apache DbUtils),但2会在堆栈中添加预处理器技术,在编译之前生成相关的JDBC代码。

    因此,基本上,如果这些解决方案涉及嵌入SQL,您也可以使用以下任何技术:

    • JPA Criteria API,将JPQL建模为Java中的内部特定于域的语言
    • jOOQ,将SQL建模为Java中的内部特定于域的语言

    可能还有其他工具可以帮助您以比SQLJ或实际字符串连接更加类型安全的方式在Java中嵌入SQL。

答案 12 :(得分:1)

根据我的经验,DAO对象中的硬编码sql语句是广泛使用的,但我认为它应该是最不受欢迎的方法。 最佳实践应该是将sql语句存储在属性文件中。并通过属性文件的接口获取DAO对象中的语句,例如 java.util.Properties 。 sql语句可以穿插'?'来传递参数,通过 Prepared Statement 方法。

这种方法有助于将sql逻辑与应用程序业务逻辑分离。这使得所有sql语句的中央存储库成为可能,这使得修改更容易,无需在应用程序逻辑中搜索数据库语句。可理解性也得到改善。

答案 13 :(得分:1)

我的资源包最终结束了。我知道这不正常,但这对我和任何“除我以外”的人来说都是最容易维持的。这很简单,合乎逻辑。

我真的很想知道是否还有人使用我的方法。

答案 14 :(得分:1)

作为 rexem 编写的SQL语句是代码 - 它们应该被视为代码,而不是外部化(unles你有充分的理由),但放置代码处理来自/到该语句的SQL数据。今天的框架ORMs / iBatis为日常的JDBC开发提供了很多简化。

您在this question找到的问题的一些答案:)您的SQL语句的存储方式取决于您的应用程序之王。你有什么需求?高安全性,易于编写代码或维护,跨平台或供应商锁定?下一个问题你需要纯SQL还是ORM框架会好吗?

* Hardcoded in business objects
* Encapsulate in separate classes e.g. Data Access Objects

最简单的解决方案(P),难以维护(C)

* Embedded in SQLJ clauses

Beter语法检查(P),缺乏od动态查询(C),性能低于JDBC(C),没有那么流行(C)

* Metadata driven (decouple the object schema from the data schema - describe the mappings between them in metadata)

必须是特定情况,你应该这样做(C)或如果你的意思是ORM(P);)

* External files (e.g. Properties or Resource files)

容易保持(P)但更难检查错误(C)

* Stored Procedures

高安全性(P)代码难以解决供应商锁定问题(C)