这在 Programmers SE 上可能会更好,但我会在这里回答。
CRUD 存储过程曾经是,有时仍然是在 SQL DBMS 上进行数据持久性和检索的最佳实践。每个这样的 DBMS 都有存储过程,因此无论编码语言和 DBMS 是什么,实际上都可以保证您能够使用该解决方案,并且使用该解决方案的代码可以指向任何具有正确存储过程的 DB,它会以最少的代码更改工作(在不同的 DBMS 中调用 SP 时需要进行一些语法更改;这些通常被集成到语言的库支持中以访问特定 DBMS 上的 SP)。也许最大的优势是集中访问表数据;您可以像 Fort Knox 一样锁定表本身,并根据需要将 SP 的访问权限分配给更有限的用户帐户。
但是,它们有一些缺点。首先,SP 很难进行 TDD,因为这些工具实际上并不存在于数据库 IDE 中;您必须在执行 SP 的其他代码中创建测试(因此测试必须使用预期的测试数据设置数据库)。从技术角度来看,这样的测试不是也不可能是“单元测试”,它是对小而窄的功能区域的小而窄的测试,没有副作用(例如读/写文件系统)。此外,SP 是在对功能进行所需更改时必须更改的另一层。向查询结果添加新字段需要更改表、检索源代码、和 SP。添加新方法来搜索特定类型的记录需要创建和测试语句,然后封装在 SP 中,并在 DAO 上创建相应的方法。
可用的新最佳实践 IMO 是一个称为对象关系映射器或 ORM 的库。 ORM 抽象了实际的数据层,因此您需要的是代码对象本身,并且您根据这些对象的属性而不是表数据来查询它们。这些查询几乎总是代码可配置的,并根据您在对象模型和数据模型之间定义的一个或多个“映射”转换为 DBMS 的 SQL 风格(类型 A 的对象作为记录保存在表 B 中,此属性 C 写入字段 D)。
优点是代码更灵活,实际上以这些代码对象的形式查找数据。查询的条件通常可以在代码中自定义;如果需要具有不同 WHERE 子句的新查询,您只需编写查询,ORM 会将其转换为新的 SQL 语句。因为 ORM 是唯一实际使用 SQL 的地方(并且大多数 ORM 使用系统存储的过程来执行可用的参数化查询字符串)注入攻击几乎是不可能的。最后,根据语言和 ORM,可以对查询进行编译器检查;在 .NET 中,提供了一个名为 Linq 的库,它提供了一种类似 SQL 的关键字语法,然后将其转换为方法调用,并提供给“查询提供程序”,该“查询提供程序”可以将这些方法调用转换为数据存储的本机查询语言。这也允许在代码中测试查询;您可以验证所使用的查询是否会在给定代表实际 DBMS 的内存对象集合的情况下产生所需的结果。
ORM 的缺点是 ORM 库通常是特定于语言的; Hibernate 在 Java 中可用,在 .NET 中的 NHibernate(以及 L2E 和 L2SQL)以及一些类似的库(如 PHP 中的 Pork)都可用,但如果您使用较旧或更深奥的语言进行编码,则根本没有可用的类型。另一个是安全性变得有点棘手。大多数 ORM 需要直接访问表才能查询和更新它们。一些人会容忍被指向用于检索的视图和用于更新的 SP(允许分离视图/SP 和表安全性以及限制可检索字段的能力),但现在您正在混合两全其美;您仍然必须定义映射,但现在您在数据层中也有代码。克服这个问题的最简单方法是在其他地方实施您的安全性;强制应用程序使用 Web 服务获取数据,该服务使用 ORM 提供数据并具有特定的、有限的“前门”。此外,许多 ORM 在以某些方式使用时会出现一些性能问题;大多数设计用于“延迟加载”数据,在实际需要数据的那一刻而不是之前检索数据,当您不需要您要求的每条记录时,这会提高前期性能。但是,当您确实需要您要求的每条记录时,这会产生额外的往返行程。您必须以特定方式构建查询,以绕过这种预期的用例行为。
哪个更好?你必须做出决定。我现在可以告诉你,使用 ORM 比 SP 更容易设置和正常工作,并且更容易对模式和查询进行更改(并限制范围)。在现代开发公司中,首要任务是使其首先工作,然后使其表现良好和/或防止入侵,这是一个巨大的优势。在大多数情况下,您认为安全是一个问题,其实不是,当安全确实是一个问题时,将解决方案放在 DB 层通常是错误的,因为 DBMS 是最后一行防御入侵;如果必须依靠 DBMS 本身来阻止不想要的事情发生,那么在它上面的许多软件和固件层中,您都没有这样做(甚至鼓励它发生)。