如何抽象数据库访问层?
How to abstract the database access layer?
所以我是软件开发的初学者,每次我必须编写一些从数据库中获取数据的程序时,我在构建该层时遇到问题,我想知道我是不是想多了。
我知道我们应该让我们的系统易于更改,而且我认为数据库供应商是可能更改的内容之一。 SQL 数据库通常保持不变,或者语言已经提供了某种形式的抽象,例如 JDBC。
但是如果新的数据源是另一种类型的数据库会发生什么,我应该提供一个单一的数据源抽象吗?我也在想,要做到这一点,我需要某种对象来解析数据,类似于 Java 中的 ResultSet,或者甚至像 String Map 这样简单的对象,并解析为我在其他地方需要的类型。但我也认为这样做可能会损害复杂性时间,将一种数据结构的数据传递给另一种更通用的数据结构。
我没有用过ORM,所以不知道他们是否提供了我想的抽象,他们是否有助于解决这个问题?
那么这通常是如何处理的呢?还是不需要不同类型数据库之间的抽象?
你熟悉 Repository 模式吗?参见 https://martinfowler.com/eaaCatalog/repository.html and https://www.baeldung.com/java-dao-vs-repository。
我会在心理上区分数据源(例如文件、数据库、API 等)和数据集(例如一堆特定记录,例如订单)。
举个例子——假设我有一个非常简单的电子商务系统,其中有两个不同的数据源:一个存储用户配置文件的 NoSQL 数据库(比方说 Mongo)和一个关系 SQL 存储订单信息的数据库(比方说 Postgres)。鉴于您提到的是 ORM,我将在 Java 或 C# 等 OO 范例中处理此问题。因此,我创建了两个域 类 - UserProfile
和 Order
。此外,我创建了两个存储库接口 - UserProfileRepository
和 OrderRepository
。所有对订单或用户配置文件进行操作的代码都将通过存储库进行操作 - 因此 persistOrder()
、getOrders()
等
然后我创建了两个接口实现 - MongoUserProfileRepository
和 PostgresOrderRepository
。使用这些存储库的所有代码仅依赖于抽象(接口)。我的 MongoUserProfileRepository
使用 Mongo 数据源并且知道如何从 Mongo 读取并将结果映射到我的其余代码可以使用的对象。这同样适用于我的 PostgresOrderRepository
- 它只使用 Postgres 数据源。
如果我也想将我的用户配置文件移动到 Postgres,我只需创建一个 PostgresUserProfileRepository
并将其传递给依赖于 UserProfileRepository
接口的所有代码。所有这些更改都集中在一个地方——只在我的存储库层中。只要数据模型看起来仍然相同,其他任何东西都不会受到更改的影响。
回答你的另一个问题 - 是的,从一个数据结构(SQL table)映射到另一个(一个对象)有一些开销,但我从来没有经历过作为一个主要问题(参见 https://www.techopedia.com/definition/32462/impedance-mismatch)。
所以我是软件开发的初学者,每次我必须编写一些从数据库中获取数据的程序时,我在构建该层时遇到问题,我想知道我是不是想多了。
我知道我们应该让我们的系统易于更改,而且我认为数据库供应商是可能更改的内容之一。 SQL 数据库通常保持不变,或者语言已经提供了某种形式的抽象,例如 JDBC。
但是如果新的数据源是另一种类型的数据库会发生什么,我应该提供一个单一的数据源抽象吗?我也在想,要做到这一点,我需要某种对象来解析数据,类似于 Java 中的 ResultSet,或者甚至像 String Map 这样简单的对象,并解析为我在其他地方需要的类型。但我也认为这样做可能会损害复杂性时间,将一种数据结构的数据传递给另一种更通用的数据结构。
我没有用过ORM,所以不知道他们是否提供了我想的抽象,他们是否有助于解决这个问题?
那么这通常是如何处理的呢?还是不需要不同类型数据库之间的抽象?
你熟悉 Repository 模式吗?参见 https://martinfowler.com/eaaCatalog/repository.html and https://www.baeldung.com/java-dao-vs-repository。
我会在心理上区分数据源(例如文件、数据库、API 等)和数据集(例如一堆特定记录,例如订单)。
举个例子——假设我有一个非常简单的电子商务系统,其中有两个不同的数据源:一个存储用户配置文件的 NoSQL 数据库(比方说 Mongo)和一个关系 SQL 存储订单信息的数据库(比方说 Postgres)。鉴于您提到的是 ORM,我将在 Java 或 C# 等 OO 范例中处理此问题。因此,我创建了两个域 类 - UserProfile
和 Order
。此外,我创建了两个存储库接口 - UserProfileRepository
和 OrderRepository
。所有对订单或用户配置文件进行操作的代码都将通过存储库进行操作 - 因此 persistOrder()
、getOrders()
等
然后我创建了两个接口实现 - MongoUserProfileRepository
和 PostgresOrderRepository
。使用这些存储库的所有代码仅依赖于抽象(接口)。我的 MongoUserProfileRepository
使用 Mongo 数据源并且知道如何从 Mongo 读取并将结果映射到我的其余代码可以使用的对象。这同样适用于我的 PostgresOrderRepository
- 它只使用 Postgres 数据源。
如果我也想将我的用户配置文件移动到 Postgres,我只需创建一个 PostgresUserProfileRepository
并将其传递给依赖于 UserProfileRepository
接口的所有代码。所有这些更改都集中在一个地方——只在我的存储库层中。只要数据模型看起来仍然相同,其他任何东西都不会受到更改的影响。
回答你的另一个问题 - 是的,从一个数据结构(SQL table)映射到另一个(一个对象)有一些开销,但我从来没有经历过作为一个主要问题(参见 https://www.techopedia.com/definition/32462/impedance-mismatch)。