虽然我掌握了总体思路,但在查看管理配置环境和管理数据库连接的最佳实践时遇到了麻烦。
含义:
如果我有存储库(例如,对于PostgreSQL),是否应该将NewRepository函数传递给数据库配置?会不会以某种方式对体系结构原理(维护,可测试性等)产生不利影响?
我们如何处理诸如db.Close()之类的事情?
我的意思是,我们显然希望它相对于作用域主要功能有所延迟,因此将代码移到存储库“类”中是有问题的(除非可以使用Context来做到这一点?)
另一方面,在主作用域中调用NewRepository,然后让db处理它外部的连接会感到很奇怪。
我发现的大多数示例都使用了main函数,因此很容易。问题是,在采用DDD(纯净/六边形)体系结构时您如何正确处理?特别是这样,所有部件都可以“插入”,而不必更改“周围”的代码。
这里是一个示例,在这里是否违反了ddd模式的某些原则?还是实际上是如何完成这些事情的?
1。我是否应该在存储库本身内部处理defer db.Close()?也许有了上下文,我可以相对于主函数作用域来推迟它,但可以在存储库本身内部进行?
2。我真的应该将配置传递到NewRepository吗?
pkg / main.go:
func main() {
// get configuration stucts via .env file
configuration, err := config.NewConfig()
if err != nil {
panic(err)
}
postgresRepo, err := postgres.NewRepository(configuration.Database)
defer postgresRepo.DB.Close()
myService := autocomplete.NewService(postgresRepo)
handler := rest.NewHandler(myService)
...
...
...
}
pkg / config / config.go:
// Config is a struct that contains configuration variables
type Config struct {
Environment string
Port string
Database *Database
}
// Database is a struct that contains DB's configuration variables
type Database struct {
Host string
Port string
User string
DB string
Password string
}
// NewConfig creates a new Config struct
func NewConfig() (*Config, error) {
env.CheckDotEnv()
port := env.MustGet("PORT")
// set default PORT if missing
if port == "" {
port = "3000"
}
return &Config{
Environment: env.MustGet("ENV"),
Port: port,
Database: &Database{
Host: env.MustGet("DATABASE_HOST"),
Port: env.MustGet("DATABASE_PORT"),
User: env.MustGet("DATABASE_USER"),
DB: env.MustGet("DATABASE_DB"),
Password: env.MustGet("DATABASE_PASSWORD"),
},
}, nil
}
答案 0 :(得分:1)
不要将数据库配置传递到存储库中,而是尝试传递数据库连接。例如:
func main() {
db, err := sql.Open("postgres", "...")
if err != nil {
log.Fatal(err)
}
defer db.Close()
repo := postgres.NewAutocompleteRepo(db)
svc := autocomplete.NewService(repo)
handler := autocomplete.NewHTTPHandler(svc)
}
这将使您有责任连接到存储库外部的数据库,并简化测试。