使用一个接口抽象多个数据源以供存储库使用
Abstracting multiple data sources with one interface for the repository to use
我正在尝试应用干净的架构,除此之外,我有一个数据源层和一个存储库层。
存储库使用接口与底层数据源(仅 sql db atm)交互,但是数据源接口是为 sql 数据库量身定制的,如下所示:
package datasource
import "database/sql"
type Source interface {
Open() error // Open the connection
Close() // Close the connection
Exec(string, ...interface{}) error // Execute a prepared query(e.g:insert)
Query(string, ...interface{}) (*sql.Rows, error) // Retrieve rows with a prepared query
}
正如我想象的那样,稍后会引入其他数据源(比如没有 sql 数据库或外部 API...),我如何将它们全部分组在一个公共接口下,以便存储库不无需了解数据来源。
谢谢。
P.S: 我知道有类似的问题但是那些从存储库的角度处理问题,我正在寻找数据源的解决方案端(例如:一个公共接口),因为我不想为每个源都有一个单独的存储库。
您选择的抽象级别不支持 database-neutral 实现。您正在等待 SQL 个查询,而您正在返回 *sql.Rows
.
如果你想成为database-independent(包括关系数据库和NoSQL数据库),你需要使用更高的抽象级别,其中术语如SQL或NoSQL查询不存在。
例如,如果您打算查询、加载和保存用户,您界面的相关部分可能如下所示:
type User struct {
ID string
// other info about users
}
type Source interface {
GetUser(id string) (*User, error)
SaveUser(u *User) error
FindUsersByFirstName(firstName string) ([]*User, error)
}
此接口不限制实现与 SQL 查询和相关对象一起使用,但它表达了您需要的操作。您应用程序的其他部分应该(必须)只能通过此接口访问数据层。所有细节(例如 SQL 查询)都属于实现。
此外,在继续进行此抽象之前,请检查其优势和所需的额外工作,因为人们通常会为极不可能发生的情况做计划。如果您从 SQL 数据库开始,您可能永远不会切换到 NoSQL 数据库。
你不能(不应该)有一个单一的数据源层来支持你想要的抽象级别的所有数据库。这将需要“开发”一种 database-independent 查询语言和一个解析器,然后您需要将其转换为特定的数据库查询。如果要支持所有数据库,最简单的方法是合并存储库和数据源层。或者放弃支持所有数据库,因为几乎 99% 的项目从不切换到根本不同的数据库。
我正在尝试应用干净的架构,除此之外,我有一个数据源层和一个存储库层。
存储库使用接口与底层数据源(仅 sql db atm)交互,但是数据源接口是为 sql 数据库量身定制的,如下所示:
package datasource
import "database/sql"
type Source interface {
Open() error // Open the connection
Close() // Close the connection
Exec(string, ...interface{}) error // Execute a prepared query(e.g:insert)
Query(string, ...interface{}) (*sql.Rows, error) // Retrieve rows with a prepared query
}
正如我想象的那样,稍后会引入其他数据源(比如没有 sql 数据库或外部 API...),我如何将它们全部分组在一个公共接口下,以便存储库不无需了解数据来源。
谢谢。
P.S: 我知道有类似的问题但是那些从存储库的角度处理问题,我正在寻找数据源的解决方案端(例如:一个公共接口),因为我不想为每个源都有一个单独的存储库。
您选择的抽象级别不支持 database-neutral 实现。您正在等待 SQL 个查询,而您正在返回 *sql.Rows
.
如果你想成为database-independent(包括关系数据库和NoSQL数据库),你需要使用更高的抽象级别,其中术语如SQL或NoSQL查询不存在。
例如,如果您打算查询、加载和保存用户,您界面的相关部分可能如下所示:
type User struct {
ID string
// other info about users
}
type Source interface {
GetUser(id string) (*User, error)
SaveUser(u *User) error
FindUsersByFirstName(firstName string) ([]*User, error)
}
此接口不限制实现与 SQL 查询和相关对象一起使用,但它表达了您需要的操作。您应用程序的其他部分应该(必须)只能通过此接口访问数据层。所有细节(例如 SQL 查询)都属于实现。
此外,在继续进行此抽象之前,请检查其优势和所需的额外工作,因为人们通常会为极不可能发生的情况做计划。如果您从 SQL 数据库开始,您可能永远不会切换到 NoSQL 数据库。
你不能(不应该)有一个单一的数据源层来支持你想要的抽象级别的所有数据库。这将需要“开发”一种 database-independent 查询语言和一个解析器,然后您需要将其转换为特定的数据库查询。如果要支持所有数据库,最简单的方法是合并存储库和数据源层。或者放弃支持所有数据库,因为几乎 99% 的项目从不切换到根本不同的数据库。